summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/Makefile2
-rw-r--r--Documentation/devicetree/bindings/arm/msm/mdm-modem.txt2
-rw-r--r--Documentation/devicetree/bindings/arm/msm/wil6210.txt8
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-rotator.txt14
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio_keys.txt3
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt57
-rw-r--r--Documentation/devicetree/bindings/media/video/laser-sensor.txt1
-rw-r--r--Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt6
-rw-r--r--Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt10
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt3
-rw-r--r--Documentation/kernel-parameters.txt10
-rw-r--r--Documentation/mic/Makefile1
-rw-r--r--Documentation/mic/mpssd/Makefile21
-rw-r--r--Documentation/networking/rmnet.txt82
-rw-r--r--Makefile2
-rw-r--r--arch/arm/boot/dts/at91-sama5d2_xplained.dts2
-rw-r--r--arch/arm/boot/dts/at91-sama5d4_xplained.dts2
-rw-r--r--arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi20
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm-audio.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm660l.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/msm-smb138x.dtsi7
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi12
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi20
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi20
-rw-r--r--arch/arm/boot/dts/qcom/msm8996-v3.dtsi75
-rw-r--r--arch/arm/boot/dts/qcom/msm8996.dtsi53
-rw-r--r--arch/arm/boot/dts/qcom/msm8996pro.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-camera.dtsi42
-rw-r--r--arch/arm/boot/dts/qcom/msm8998-regulator.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-camera.dtsi42
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-gpu.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi62
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-mdss.dtsi14
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-pm.dtsi128
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts32
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-qrd.dtsi13
-rw-r--r--arch/arm/boot/dts/qcom/sdm630-regulator.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/sdm630.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-audio.dtsi2
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-bus.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-camera-sensor-cdp.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-camera.dtsi42
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-gpu.dtsi3
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-mdss.dtsi13
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-qrd.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/sdm660-regulator.dtsi1
-rw-r--r--arch/arm/configs/sdm660-perf_defconfig1
-rw-r--r--arch/arm/configs/sdm660_defconfig1
-rw-r--r--arch/arm/include/asm/kvm_mmu.h9
-rw-r--r--arch/arm/lib/getuser.S2
-rw-r--r--arch/arm64/configs/msm-perf_defconfig1
-rw-r--r--arch/arm64/configs/msm_defconfig1
-rw-r--r--arch/arm64/configs/msmcortex_mediabox_defconfig1
-rw-r--r--arch/arm64/configs/sdm660-perf_defconfig1
-rw-r--r--arch/arm64/configs/sdm660_defconfig2
-rw-r--r--arch/arm64/include/asm/kvm_mmu.h3
-rw-r--r--arch/arm64/kernel/head.S4
-rw-r--r--arch/arm64/kernel/kaslr.c10
-rw-r--r--arch/mips/bcm47xx/buttons.c10
-rw-r--r--arch/mips/cavium-octeon/octeon-memcpy.S20
-rw-r--r--arch/mips/configs/ip22_defconfig4
-rw-r--r--arch/mips/configs/ip27_defconfig3
-rw-r--r--arch/mips/configs/lemote2f_defconfig2
-rw-r--r--arch/mips/configs/malta_defconfig4
-rw-r--r--arch/mips/configs/malta_kvm_defconfig4
-rw-r--r--arch/mips/configs/malta_kvm_guest_defconfig4
-rw-r--r--arch/mips/configs/maltaup_xpa_defconfig4
-rw-r--r--arch/mips/configs/nlm_xlp_defconfig2
-rw-r--r--arch/mips/configs/nlm_xlr_defconfig2
-rw-r--r--arch/mips/dec/int-handler.S40
-rw-r--r--arch/mips/include/asm/checksum.h2
-rw-r--r--arch/mips/kernel/process.c151
-rw-r--r--arch/mips/lantiq/xway/sysctrl.c8
-rw-r--r--arch/mips/mm/sc-ip22.c54
-rw-r--r--arch/mips/netlogic/common/reset.S11
-rw-r--r--arch/mips/netlogic/common/smpboot.S4
-rw-r--r--arch/mips/ralink/prom.c9
-rw-r--r--arch/mips/ralink/rt288x.c10
-rw-r--r--arch/mips/ralink/rt305x.c11
-rw-r--r--arch/mips/ralink/rt3883.c10
-rw-r--r--arch/mips/sgi-ip22/Platform2
-rw-r--r--arch/powerpc/kernel/hw_breakpoint.c4
-rw-r--r--arch/powerpc/lib/sstep.c20
-rw-r--r--arch/s390/include/asm/processor.h3
-rw-r--r--arch/s390/kernel/crash_dump.c18
-rw-r--r--arch/s390/kernel/setup.c8
-rw-r--r--arch/s390/kvm/kvm-s390.c3
-rw-r--r--arch/s390/mm/pgtable.c19
-rw-r--r--arch/x86/kvm/vmx.c60
-rw-r--r--arch/x86/platform/goldfish/goldfish.c14
-rw-r--r--arch/xtensa/kernel/setup.c4
-rw-r--r--block/blk-core.c2
-rw-r--r--block/blk-mq.c17
-rw-r--r--block/genhd.c5
-rw-r--r--crypto/Makefile2
-rw-r--r--crypto/testmgr.h2
-rw-r--r--drivers/acpi/nfit.c16
-rw-r--r--drivers/bcma/main.c4
-rw-r--r--drivers/block/loop.c32
-rw-r--r--drivers/bluetooth/ath3k.c2
-rw-r--r--drivers/bluetooth/btusb.c1
-rw-r--r--drivers/char/diag/diag_debugfs.c11
-rw-r--r--drivers/char/diag/diag_masks.c2
-rw-r--r--drivers/char/diag/diag_memorydevice.c60
-rw-r--r--drivers/char/diag/diag_mux.c57
-rw-r--r--drivers/char/diag/diagchar.h32
-rw-r--r--drivers/char/diag/diagchar_core.c91
-rw-r--r--drivers/char/diag/diagfwd.c3
-rw-r--r--drivers/char/diag/diagfwd.h2
-rw-r--r--drivers/char/diag/diagfwd_cntl.c22
-rw-r--r--drivers/char/diag/diagfwd_cntl.h6
-rw-r--r--drivers/char/diag/diagfwd_peripheral.c322
-rw-r--r--drivers/char/diag/diagfwd_peripheral.h4
-rw-r--r--drivers/char/hw_random/msm-rng.c3
-rw-r--r--drivers/clk/msm/clock-gcc-8996.c10
-rw-r--r--drivers/clk/msm/clock-gcc-8998.c14
-rw-r--r--drivers/cpuidle/lpm-levels.c15
-rw-r--r--drivers/devfreq/governor_spdm_bw_hyp.c6
-rw-r--r--drivers/dma/ipu/ipu_irq.c2
-rw-r--r--drivers/esoc/esoc-mdm-4x.c4
-rw-r--r--drivers/esoc/esoc.h4
-rw-r--r--drivers/esoc/esoc_bus.c9
-rw-r--r--drivers/esoc/esoc_client.c14
-rw-r--r--drivers/esoc/esoc_dev.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v11_0.c6
-rw-r--r--drivers/gpu/drm/ast/ast_post.c48
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c2
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c2
-rw-r--r--drivers/gpu/drm/drm_edid.c3
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c13
-rw-r--r--drivers/gpu/drm/msm/Makefile3
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx.xml.h36
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_counters.c689
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.c13
-rw-r--r--drivers/gpu/drm/msm/adreno/a5xx_gpu.h2
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.c49
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_gpu.h32
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c46
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h1
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c3
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.c115
-rw-r--r--drivers/gpu/drm/msm/msm_gpu.h16
-rw-r--r--drivers/gpu/drm/radeon/radeon_cursor.c4
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c4
-rw-r--r--drivers/hv/hv.c10
-rw-r--r--drivers/hv/hv_fcopy.c4
-rw-r--r--drivers/hv/hv_kvp.c4
-rw-r--r--drivers/hv/hv_snapshot.c4
-rw-r--r--drivers/i2c/busses/i2c-msm-v2.c27
-rw-r--r--drivers/iio/adc/qcom-rradc.c102
-rw-r--r--drivers/iio/adc/qcom-tadc.c224
-rw-r--r--drivers/iio/pressure/mpl115.c1
-rw-r--r--drivers/iio/pressure/mpl3115.c4
-rw-r--r--drivers/infiniband/core/cma.c3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c12
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c36
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c49
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h1
-rw-r--r--drivers/input/keyboard/gpio_keys.c77
-rw-r--r--drivers/input/mouse/elan_i2c_core.c1
-rw-r--r--drivers/input/touchscreen/Kconfig11
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c16
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig127
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/Makefile17
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_active_pen.c624
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c4711
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h500
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c4440
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c2308
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c712
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_proximity.c692
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c1058
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_hid_i2c.c1006
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_spi.c634
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c4162
-rw-r--r--drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c416
-rw-r--r--drivers/iommu/intel-iommu.c3
-rw-r--r--drivers/md/bcache/bcache.h4
-rw-r--r--drivers/md/bcache/btree.c40
-rw-r--r--drivers/md/bcache/btree.h3
-rw-r--r--drivers/md/bcache/request.c4
-rw-r--r--drivers/md/bcache/super.c2
-rw-r--r--drivers/md/dm-cache-target.c6
-rw-r--r--drivers/md/dm-stats.c1
-rw-r--r--drivers/md/dm.c55
-rw-r--r--drivers/md/linear.c39
-rw-r--r--drivers/md/linear.h1
-rw-r--r--drivers/media/pci/dm1105/Kconfig2
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/camera/camera.c5
-rw-r--r--drivers/media/platform/msm/camera_v2/common/cam_soc_api.c17
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp.c13
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp.h25
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp32.c4
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp40.c5
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp44.c5
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp46.c5
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp47.c82
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp47.h6
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp48.c2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c104
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c6
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c114
-rw-r--r--drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c2
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_base.c17
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_base.h1
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_core.c17
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c20
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c9
-rw-r--r--drivers/media/usb/siano/smsusb.c18
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c2
-rw-r--r--drivers/mfd/wcd934x-regmap.c15
-rw-r--r--drivers/misc/hdcp.c5
-rw-r--r--drivers/misc/qseecom_kernel.h4
-rw-r--r--drivers/mmc/core/mmc.c4
-rw-r--r--drivers/mmc/host/sdhci-msm.c27
-rw-r--r--drivers/mmc/host/sdhci-msm.h7
-rw-r--r--drivers/mtd/maps/pmcmsp-flash.c4
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/can/usb/usb_8dev.c9
-rw-r--r--drivers/net/ethernet/marvell/mvpp2.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c5
-rw-r--r--drivers/net/ethernet/ti/cpmac.c2
-rw-r--r--drivers/net/ieee802154/fakelb.c14
-rw-r--r--drivers/net/loopback.c1
-rw-r--r--drivers/net/macvtap.c4
-rw-r--r--drivers/net/rmnet/Kconfig21
-rw-r--r--drivers/net/rmnet/Makefile14
-rw-r--r--drivers/net/rmnet/rmnet_config.c1157
-rw-r--r--drivers/net/rmnet/rmnet_config.h107
-rw-r--r--drivers/net/rmnet/rmnet_handlers.c550
-rw-r--r--drivers/net/rmnet/rmnet_handlers.h24
-rw-r--r--drivers/net/rmnet/rmnet_main.c60
-rw-r--r--drivers/net/rmnet/rmnet_map.h100
-rw-r--r--drivers/net/rmnet/rmnet_map_command.c180
-rw-r--r--drivers/net/rmnet/rmnet_map_data.c147
-rw-r--r--drivers/net/rmnet/rmnet_private.h76
-rw-r--r--drivers/net/rmnet/rmnet_stats.c86
-rw-r--r--drivers/net/rmnet/rmnet_stats.h61
-rw-r--r--drivers/net/rmnet/rmnet_vnd.c457
-rw-r--r--drivers/net/rmnet/rmnet_vnd.h34
-rw-r--r--drivers/net/tun.c10
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath10k/Makefile2
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c6
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h31
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c243
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h15
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c3
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.c865
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.h156
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c82
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.h98
-rw-r--r--drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.c2091
-rw-r--r--drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.h619
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c44
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c27
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c21
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c20
-rw-r--r--drivers/net/wireless/cnss_genl/Kconfig7
-rw-r--r--drivers/net/wireless/cnss_genl/Makefile1
-rw-r--r--drivers/net/wireless/cnss_genl/cnss_nl.c204
-rw-r--r--drivers/net/wireless/cnss_prealloc/cnss_prealloc.c89
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/pci.h4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/usb.c19
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/usb.h3
-rw-r--r--drivers/ntb/ntb_transport.c5
-rw-r--r--drivers/nvdimm/namespace_devs.c28
-rw-r--r--drivers/nvdimm/nd.h1
-rw-r--r--drivers/nvdimm/region_devs.c9
-rw-r--r--drivers/pci/host/pci-msm.c52
-rw-r--r--drivers/pinctrl/qcom/pinctrl-lpi.c4
-rw-r--r--drivers/platform/goldfish/pdev_bus.c13
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_flt.c9
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c3
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_flt.c7
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c19
-rw-r--r--drivers/platform/msm/mhi/mhi.h81
-rw-r--r--drivers/platform/msm/mhi/mhi_bhi.c176
-rw-r--r--drivers/platform/msm/mhi/mhi_bhi.h3
-rw-r--r--drivers/platform/msm/mhi/mhi_event.c8
-rw-r--r--drivers/platform/msm/mhi/mhi_iface.c1
-rw-r--r--drivers/platform/msm/mhi/mhi_isr.c117
-rw-r--r--drivers/platform/msm/mhi/mhi_main.c183
-rw-r--r--drivers/platform/msm/mhi/mhi_pm.c171
-rw-r--r--drivers/platform/msm/mhi/mhi_ssr.c368
-rw-r--r--drivers/platform/msm/mhi/mhi_states.c399
-rw-r--r--drivers/platform/msm/mhi/mhi_sys.c18
-rw-r--r--drivers/platform/msm/mhi_uci/mhi_uci.c1037
-rw-r--r--drivers/platform/msm/msm_11ad/msm_11ad.c122
-rw-r--r--drivers/platform/msm/msm_ext_display.c18
-rw-r--r--drivers/power/power_supply_sysfs.c1
-rw-r--r--drivers/power/supply/qcom/fg-core.h14
-rw-r--r--drivers/power/supply/qcom/fg-memif.c94
-rw-r--r--drivers/power/supply/qcom/pmic-voter.c2
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c145
-rw-r--r--drivers/power/supply/qcom/qpnp-qnovo.c473
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c28
-rw-r--r--drivers/power/supply/qcom/smb-lib.c102
-rw-r--r--drivers/power/supply/qcom/smb-lib.h8
-rw-r--r--drivers/power/supply/qcom/smb-reg.h2
-rw-r--r--drivers/power/supply/qcom/smb138x-charger.c39
-rw-r--r--drivers/pwm/pwm-pca9685.c11
-rw-r--r--drivers/regulator/core.c5
-rw-r--r--drivers/regulator/qpnp-lcdb-regulator.c113
-rw-r--r--drivers/rtc/interface.c16
-rw-r--r--drivers/rtc/rtc-sun6i.c23
-rw-r--r--drivers/s390/block/dcssblk.c2
-rw-r--r--drivers/s390/cio/qdio_thinint.c8
-rw-r--r--drivers/scsi/aacraid/src.c21
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c9
-rw-r--r--drivers/scsi/mvsas/mv_sas.c4
-rw-r--r--drivers/scsi/scsi_dh.c22
-rw-r--r--drivers/scsi/scsi_lib.c26
-rw-r--r--drivers/scsi/sg.c4
-rw-r--r--drivers/scsi/storvsc_drv.c32
-rw-r--r--drivers/scsi/ufs/ufshcd.c2
-rw-r--r--drivers/soc/qcom/glink_private.h5
-rw-r--r--drivers/soc/qcom/glink_ssr.c84
-rw-r--r--drivers/soc/qcom/icnss.c120
-rw-r--r--drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c3
-rw-r--r--drivers/soc/qcom/msm_bus/msm_bus_fabric_adhoc.c2
-rw-r--r--drivers/soc/qcom/peripheral-loader.c2
-rw-r--r--drivers/soc/qcom/qdsp6v2/apr_tal_glink.c3
-rw-r--r--drivers/soc/qcom/qdsp6v2/audio_notifier.c2
-rw-r--r--drivers/soc/qcom/qpnp-haptic.c37
-rw-r--r--drivers/soc/qcom/service-locator.c7
-rw-r--r--drivers/soc/qcom/service-notifier.c22
-rw-r--r--drivers/soc/qcom/spcom.c4
-rw-r--r--drivers/soc/qcom/wcd-dsp-glink.c8
-rw-r--r--drivers/soundwire/swr-wcd-ctrl.c20
-rwxr-xr-xdrivers/soundwire/swr-wcd-ctrl.h7
-rwxr-xr-xdrivers/soundwire/swrm_registers.h3
-rw-r--r--drivers/staging/android/ion/ion.c16
-rw-r--r--drivers/staging/android/ion/ion_system_heap.c8
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_recv.c3
-rw-r--r--drivers/staging/rtl8712/rtl871x_recv.c7
-rw-r--r--drivers/target/iscsi/iscsi_target.c2
-rw-r--r--drivers/target/target_core_device.c10
-rw-r--r--drivers/target/target_core_tpg.c45
-rw-r--r--drivers/target/target_core_transport.c116
-rw-r--r--drivers/thermal/msm_thermal-dev.c7
-rw-r--r--drivers/tty/n_hdlc.c143
-rw-r--r--drivers/tty/serial/8250/8250_pci.c13
-rw-r--r--drivers/tty/serial/msm_serial.c1
-rw-r--r--drivers/tty/serial/msm_serial_hs.c36
-rw-r--r--drivers/tty/serial/samsung.c6
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c1
-rw-r--r--drivers/usb/dwc3/core.c34
-rw-r--r--drivers/usb/dwc3/core.h31
-rw-r--r--drivers/usb/dwc3/dwc3-msm.c3
-rw-r--r--drivers/usb/dwc3/gadget.c30
-rw-r--r--drivers/usb/dwc3/gadget.h15
-rw-r--r--drivers/usb/gadget/configfs.c17
-rw-r--r--drivers/usb/gadget/function/Makefile2
-rw-r--r--drivers/usb/gadget/function/f_audio_source.c9
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c7
-rw-r--r--drivers/usb/gadget/function/f_mtp.c1
-rw-r--r--drivers/usb/gadget/function/f_ncm.c58
-rw-r--r--drivers/usb/gadget/function/f_qdss.c19
-rw-r--r--drivers/usb/gadget/function/f_qdss.h5
-rw-r--r--drivers/usb/gadget/function/u_qdss.c22
-rw-r--r--drivers/usb/gadget/udc/dummy_hcd.c2
-rw-r--r--drivers/usb/gadget/udc/fsl_udc_core.c10
-rw-r--r--drivers/usb/host/xhci-dbg.c2
-rw-r--r--drivers/usb/host/xhci-plat.c10
-rw-r--r--drivers/usb/host/xhci.c8
-rw-r--r--drivers/usb/misc/iowarrior.c21
-rw-r--r--drivers/usb/musb/da8xx.c6
-rw-r--r--drivers/usb/phy/phy-msm-ssusb-qmp.c178
-rw-r--r--drivers/usb/serial/ark3116.c13
-rw-r--r--drivers/usb/serial/cp210x.c2
-rw-r--r--drivers/usb/serial/digi_acceleport.c14
-rw-r--r--drivers/usb/serial/ftdi_sio.c31
-rw-r--r--drivers/usb/serial/io_ti.c8
-rw-r--r--drivers/usb/serial/mos7840.c4
-rw-r--r--drivers/usb/serial/omninet.c6
-rw-r--r--drivers/usb/serial/opticon.c2
-rw-r--r--drivers/usb/serial/safe_serial.c5
-rw-r--r--drivers/usb/serial/spcp8x5.c8
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.c47
-rw-r--r--drivers/video/fbdev/msm/mdss_dp.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_dp_aux.c48
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c9
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_host.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c10
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c5
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.c31
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c39
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c71
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c18
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_layer.c16
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c66
-rw-r--r--drivers/video/fbdev/msm/msm_mdss_io_8974.c6
-rw-r--r--drivers/w1/masters/ds2490.c142
-rw-r--r--drivers/w1/w1.c1
-rw-r--r--fs/ceph/mds_client.c5
-rw-r--r--fs/ext4/extents.c27
-rw-r--r--fs/ext4/inline.c9
-rw-r--r--fs/ext4/inode.c43
-rw-r--r--fs/ext4/mballoc.c7
-rw-r--r--fs/ext4/super.c9
-rw-r--r--fs/f2fs/data.c4
-rw-r--r--fs/f2fs/f2fs.h1
-rw-r--r--fs/f2fs/super.c2
-rw-r--r--fs/fat/fatent.c7
-rw-r--r--fs/fat/inode.c18
-rw-r--r--fs/fuse/file.c1
-rw-r--r--fs/gfs2/glock.c5
-rw-r--r--fs/jbd2/transaction.c4
-rw-r--r--fs/mount.h1
-rw-r--r--fs/namespace.c109
-rw-r--r--fs/nfs/nfs4proc.c10
-rw-r--r--fs/nfs/nfs4xdr.c2
-rw-r--r--fs/nfsd/vfs.c59
-rw-r--r--fs/pnode.c61
-rw-r--r--fs/pnode.h2
-rw-r--r--fs/splice.c1
-rw-r--r--include/dt-bindings/clock/msm-clocks-8996.h2
-rw-r--r--include/dt-bindings/clock/msm-clocks-hwio-8996.h3
-rw-r--r--include/linux/can/core.h7
-rw-r--r--include/linux/ceph/osdmap.h2
-rw-r--r--include/linux/diagchar.h1
-rw-r--r--include/linux/esoc_client.h3
-rw-r--r--include/linux/gpio_keys.h3
-rw-r--r--include/linux/i2c/i2c-msm-v2.h3
-rw-r--r--include/linux/input/synaptics_dsx_v2_6.h115
-rw-r--r--include/linux/intel-iommu.h14
-rw-r--r--include/linux/libnvdimm.h2
-rw-r--r--include/linux/lockd/lockd.h3
-rw-r--r--include/linux/msm_ext_display.h4
-rw-r--r--include/linux/msm_mhi.h31
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--include/linux/power_supply.h1
-rw-r--r--include/linux/qpnp/qpnp-revid.h29
-rw-r--r--include/media/msmb_pproc.h4
-rw-r--r--include/net/cipso_ipv4.h4
-rw-r--r--include/net/cnss_nl.h100
-rw-r--r--include/rdma/ib_sa.h6
-rw-r--r--include/scsi/scsi_device.h1
-rw-r--r--include/soc/at91/at91sam9_ddrsdr.h3
-rw-r--r--include/soc/qcom/icnss.h5
-rw-r--r--include/sound/apr_audio-v2.h5
-rw-r--r--include/sound/q6asm-v2.h3
-rw-r--r--include/target/target_core_base.h2
-rw-r--r--include/target/target_core_fabric.h2
-rw-r--r--include/trace/events/syscalls.h1
-rw-r--r--include/uapi/drm/msm_drm.h71
-rw-r--r--include/uapi/linux/Kbuild1
-rw-r--r--include/uapi/linux/esoc_ctrl.h10
-rw-r--r--include/uapi/linux/rmnet.h213
-rw-r--r--include/uapi/linux/rmnet_data.h15
-rw-r--r--include/uapi/media/msm_media_info.h12
-rw-r--r--ipc/shm.c13
-rw-r--r--kernel/futex.c2
-rw-r--r--kernel/membarrier.c4
-rw-r--r--kernel/printk/printk.c2
-rw-r--r--kernel/sched/core.c4
-rw-r--r--kernel/sched/core_ctl.c45
-rw-r--r--kernel/trace/ipc_logging.c6
-rw-r--r--mm/backing-dev.c9
-rw-r--r--mm/filemap.c7
-rw-r--r--mm/memcontrol.c36
-rw-r--r--mm/page_alloc.c2
-rw-r--r--net/can/af_can.c12
-rw-r--r--net/can/af_can.h3
-rw-r--r--net/can/bcm.c4
-rw-r--r--net/can/gw.c2
-rw-r--r--net/can/raw.c4
-rw-r--r--net/core/dev.c31
-rw-r--r--net/dccp/input.c3
-rw-r--r--net/ethernet/eth.c1
-rw-r--r--net/ipv4/cipso_ipv4.c4
-rw-r--r--net/ipv4/ip_sockglue.c17
-rw-r--r--net/ipv4/ping.c2
-rw-r--r--net/ipv4/tcp.c6
-rw-r--r--net/ipv4/tcp_output.c6
-rw-r--r--net/ipv6/ip6_gre.c41
-rw-r--r--net/ipv6/ip6_tunnel.c34
-rw-r--r--net/ipv6/sit.c1
-rw-r--r--net/ipv6/tcp_ipv6.c24
-rw-r--r--net/ipv6/udp.c59
-rw-r--r--net/irda/irqueue.c34
-rw-r--r--net/l2tp/l2tp_core.h1
-rw-r--r--net/l2tp/l2tp_ip.c27
-rw-r--r--net/l2tp/l2tp_ip6.c2
-rw-r--r--net/llc/llc_conn.c3
-rw-r--r--net/llc/llc_sap.c3
-rw-r--r--net/mac80211/pm.c1
-rw-r--r--net/packet/af_packet.c79
-rw-r--r--net/rmnet_data/rmnet_data_config.c30
-rw-r--r--net/rmnet_data/rmnet_data_config.h1
-rw-r--r--net/rmnet_data/rmnet_data_vnd.c15
-rw-r--r--net/rmnet_data/rmnet_data_vnd.h4
-rw-r--r--net/sctp/socket.c3
-rw-r--r--net/socket.c4
-rw-r--r--net/wireless/db.txt2
-rw-r--r--samples/mic/mpssd/.gitignore (renamed from Documentation/mic/mpssd/.gitignore)0
-rw-r--r--samples/mic/mpssd/Makefile27
-rw-r--r--[-rwxr-xr-x]samples/mic/mpssd/micctrl (renamed from Documentation/mic/mpssd/micctrl)0
-rw-r--r--[-rwxr-xr-x]samples/mic/mpssd/mpss (renamed from Documentation/mic/mpssd/mpss)0
-rw-r--r--samples/mic/mpssd/mpssd.c (renamed from Documentation/mic/mpssd/mpssd.c)0
-rw-r--r--samples/mic/mpssd/mpssd.h (renamed from Documentation/mic/mpssd/mpssd.h)0
-rw-r--r--samples/mic/mpssd/sysfs.c (renamed from Documentation/mic/mpssd/sysfs.c)0
-rw-r--r--samples/seccomp/bpf-helper.h125
-rw-r--r--sound/core/seq/seq_fifo.c3
-rw-r--r--sound/core/timer.c18
-rw-r--r--sound/pci/ctxfi/cthw20k1.c19
-rw-r--r--sound/pci/ctxfi/cthw20k2.c19
-rw-r--r--sound/pci/hda/hda_intel.c4
-rw-r--r--sound/pci/hda/patch_realtek.c8
-rw-r--r--sound/soc/codecs/audio-ext-clk-up.c36
-rw-r--r--sound/soc/codecs/msm_sdw/msm_sdw_cdc.c16
-rw-r--r--sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c18
-rw-r--r--sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c16
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.c38
-rw-r--r--sound/soc/codecs/wcd-spi.c75
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c18
-rw-r--r--sound/soc/codecs/wcd9xxx-resmgr-v2.c8
-rw-r--r--sound/soc/codecs/wcd9xxx-resmgr-v2.h5
-rw-r--r--sound/soc/codecs/wsa881x.c39
-rw-r--r--sound/soc/msm/msm8998.c1
-rw-r--r--sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c209
-rw-r--r--sound/soc/msm/qdsp6v2/msm-lsm-client.c27
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c211
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c1
-rw-r--r--sound/soc/msm/qdsp6v2/msm-qti-pp-config.c130
-rw-r--r--sound/soc/msm/qdsp6v2/msm-qti-pp-config.h14
-rw-r--r--sound/soc/msm/qdsp6v2/q6asm.c92
-rw-r--r--sound/soc/msm/sdm660-ext-dai-links.c1
-rwxr-xr-xtools/testing/ktest/ktest.pl2
556 files changed, 17380 insertions, 25176 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile
index bc0548201755..fc759598c4c9 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -1,4 +1,4 @@
subdir-y := accounting auxdisplay blackfin connector \
- filesystems filesystems ia64 laptops mic misc-devices \
+ filesystems filesystems ia64 laptops misc-devices \
networking pcmcia prctl ptp spi timers vDSO video4linux \
watchdog
diff --git a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
index 6ddc72576e88..a6537ebd2512 100644
--- a/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
+++ b/Documentation/devicetree/bindings/arm/msm/mdm-modem.txt
@@ -108,6 +108,8 @@ Optional driver parameters:
- qcom,sysmon-id: platform device id that sysmon is probed with for the subsystem.
- qcom,pil-force-shutdown: Boolean. If set, the SSR framework will not trigger graceful shutdown
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.
Example:
mdm0: qcom,mdm0 {
diff --git a/Documentation/devicetree/bindings/arm/msm/wil6210.txt b/Documentation/devicetree/bindings/arm/msm/wil6210.txt
index b381bdebdfc9..c4673279953d 100644
--- a/Documentation/devicetree/bindings/arm/msm/wil6210.txt
+++ b/Documentation/devicetree/bindings/arm/msm/wil6210.txt
@@ -10,6 +10,10 @@ Required properties:
- compatible: "qcom,wil6210"
- qcom,smmu-support: Boolean flag indicating whether PCIe has SMMU support
+- qcom,smmu-s1-en: Boolean flag indicating whether SMMU stage1 should be enabled
+- qcom,smmu-fast-map: Boolean flag indicating whether SMMU fast mapping should be enabled
+- qcom,smmu-coherent: Boolean flag indicating SMMU dma and page table coherency
+- qcom,smmu-mapping: specifies the base address and size of SMMU space
- qcom,pcie-parent: phandle for the PCIe root complex to which 11ad card is connected
- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
the below optional properties:
@@ -33,6 +37,10 @@ Example:
wil6210: qcom,wil6210 {
compatible = "qcom,wil6210";
qcom,smmu-support;
+ qcom,smmu-s1-en;
+ qcom,smmu-fast-map;
+ qcom,smmu-coherent;
+ qcom,smmu-mapping = <0x20000000 0xe0000000>;
qcom,pcie-parent = <&pcie1>;
qcom,wigig-en = <&tlmm 94 0>;
qcom,msm-bus,name = "wil6210";
diff --git a/Documentation/devicetree/bindings/fb/mdss-rotator.txt b/Documentation/devicetree/bindings/fb/mdss-rotator.txt
index 5e077ac23819..d424201cd427 100644
--- a/Documentation/devicetree/bindings/fb/mdss-rotator.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-rotator.txt
@@ -53,6 +53,8 @@ Optional properties
bandwidth compression (ubwc)
- qcom,mdss-has-downscale Boolean property to indicate
if the hw supports downscale
+- qcom,sde-reg-bus: Subnode to provide Bus scaling for register access for
+ rotator
Example:
mdss_rotator: qcom,mdss_rotator {
@@ -75,4 +77,16 @@ Example:
vdd-supply = <&gdsc_mdss>;
gdsc-mmagic-mdss-supply = <&gdsc_mmagic_mdss>;
qcom,supply-names = "vdd", "gdsc-mmagic-mdss";
+ qcom,sde-reg-bus {
+ /* Reg Bus Scale Settings */
+ qcom,msm-bus,name = "mdss_rot_reg";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,vectors-KBps =
+ <1 590 0 0>,
+ <1 590 0 76800>,
+ <1 590 0 160000>,
+ <1 590 0 320000>;
+ };
};
diff --git a/Documentation/devicetree/bindings/gpio/gpio_keys.txt b/Documentation/devicetree/bindings/gpio/gpio_keys.txt
index 0a9b31a946ec..3688e3ebab48 100644
--- a/Documentation/devicetree/bindings/gpio/gpio_keys.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio_keys.txt
@@ -15,6 +15,8 @@ Optional properties:
config defined in pin groups of interrupt and reset gpio.
"gpio_ts_suspend" : Disabled configuration of pins, this should specify sleep
config defined in pin groups of interrupt and reset gpio.
+ - name : input device name.
+ - use-syscore : use syscore functionality for driver.
Each button (key) is represented as a sub-node of "gpio-keys":
Subnode properties:
@@ -41,6 +43,7 @@ gpio_keys {
pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
pinctrl-0 = <&gpio_key_active>;
pinctrl-1 = <&gpio_key_suspend>;
+ use-syscore;
button@21 {
label = "GPIO Key UP";
linux,code = <103>;
diff --git a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt
deleted file mode 100644
index c10fd981df2b..000000000000
--- a/Documentation/devicetree/bindings/input/touchscreen/synaptics_dsxv26_i2c.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-Synaptics DSXV26 touch controller
-
-Please add this description here: The Synaptics Touch controller is connected to the
-host processor via I2C. The controller generates interrupts when the user touches
-the panel. The host controller is expected to read the touch coordinates over I2C and
-pass the coordinates to the rest of the system.
-
-Required properties:
-
- - compatible : should be "synaptics,dsx-i2c".
- - reg : i2c slave address of the device.
- - interrupt-parent : parent of interrupt.
- - synaptics,irq-gpio : irq gpio.
- - synaptics,irq-flags : irq flags.
-
-Optional property:
- - vdd_ana-supply : digital voltage power supply needed to power device.
- - vcc_i2c-supply : analog voltage power supply needed to power device.
- - synaptics,pwr-reg-name : power reg name of digital voltage.
- - synaptics,bus-reg-name : bus reg name of analog voltage.
- - synaptics,irq-on-state : status of irq gpio.
- - synaptics,cap-button-codes : virtual key code mappings to be used.
- - synaptics,vir-button-codes : virtual key code and the response region on panel.
- - synaptics,x-flip : modify orientation of the x axis.
- - synaptics,y-flip : modify orientation of the y axis.
- - synaptics,reset-delay-ms : reset delay for controller (ms), default 100.
- - synaptics,max-y-for-2d : maximal y value of the panel.
- - clock-names : Clock names used for secure touch. They are: "iface_clk", "core_clk"
- - clocks : Defined if 'clock-names' DT property is defined. These clocks
- are associated with the underlying I2C bus.
-
-Example:
- i2c@78b7000 {
- status = "ok";
- synaptics@4b {
- compatible = "synaptics,dsx-i2c";
- reg = <0x4b>;
- interrupt-parent = <&tlmm>;
- interrupts = <65 0x2008>;
- vdd_ana-supply = <&pmtitanium_l17>;
- vcc_i2c-supply = <&pmtitanium_l6>;
- synaptics,pwr-reg-name = "vdd_ana";
- synaptics,bus-reg-name = "vcc_i2c";
- synaptics,irq-gpio = <&tlmm 65 0x2008>;
- synaptics,irq-on-state = <0>;
- synaptics,irq-flags = <0x2008>; /* IRQF_ONESHOT | IRQF_TRIGGER_LOW */
- synaptics,power-delay-ms = <200>;
- synaptics,reset-delay-ms = <200>;
- synaptics,max-y-for-2d = <1919>; /* remove if no virtual buttons */
- synaptics,cap-button-codes = <139 172 158>;
- synaptics,vir-button-codes = <139 180 2000 320 160 172 540 2000 320 160 158 900 2000 320 160>;
- /* Underlying clocks used by secure touch */
- clock-names = "iface_clk", "core_clk";
- clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
- <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>;
- };
- };
diff --git a/Documentation/devicetree/bindings/media/video/laser-sensor.txt b/Documentation/devicetree/bindings/media/video/laser-sensor.txt
index 1bcb0b93cb10..0003f20845a0 100644
--- a/Documentation/devicetree/bindings/media/video/laser-sensor.txt
+++ b/Documentation/devicetree/bindings/media/video/laser-sensor.txt
@@ -19,6 +19,7 @@ Required node properties:
regulators used
- pinctrl-names : should specify the pin control groups followed by
the definition of each group
+ stm,irq-gpio : irq gpio which is to provide interrupts to host.
- gpios : should contain phandle to gpio controller node and array of
#gpio-cells specifying specific gpio (controller specific)
- qcom,gpio-req-tbl-num : contains index to gpios specific to the sensor
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
index c8f2a5a8e496..92ef23c3a290 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/smb138x-charger.txt
@@ -31,6 +31,12 @@ Charger specific properties:
revid module. This is used to identify
the SMB subtype.
+- qcom,parallel-mode
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies parallel charging mode. If not specified, MID-MID
+ option is selected by default.
+
- qcom,suspend-input
Usage: optional
Value type: <empty>
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
index 63da8ecbfa4c..ed383ce9ea8f 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
@@ -26,12 +26,10 @@ First Level Node - LCDB module
Value type: <prop-encoded-array>
Definition: Base address of the LCDB SPMI peripheral.
-- qcom,force-module-reenable
- Usage: required if using SW mode for module enable
- Value type: <bool>
- Definition: This enables the workaround to force enable
- the vph_pwr_2p5_ok signal required for
- turning on the LCDB module.
+- qcom,pmic-revid
+ Usage: required
+ Value type: <phandle>
+ Definition: Phandle to the PMIC's revid node
Touch-to-wake (TTW) properties:
diff --git a/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt b/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt
index 17a510a5ee6a..337649824257 100644
--- a/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt
+++ b/Documentation/devicetree/bindings/soc/qcom/qpnp-haptic.txt
@@ -66,6 +66,9 @@ Optional properties when qcom,actuator-type is "lra"
- qcom,lra-high-z : High Z configuration for auto resonance. Possible string values are
"none", "opt1", "opt2" and "opt3" (default). For PM660,
"opt0" is valid value for 1 LRA period.
+ - qcom,lra-hw-auto-resonance : boolean, enable Hardware auto-resonance for PM660.
+ Use this property to enable Hardware auto-resonance.
+ If not defined then Software auto-resonance is enabled(default).
- qcom,lra-qwd-drive-duration : Drive duration of LRA in QWD mode for PM660.
Possible values are: 0: 1/4 LRA PERIOD and 1: 3/8 LRA PERIOD
- qcom,lra-calibrate-at-eop : To calibrate at End of Pattern for PM660.
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 45d680644dfe..0220f18658e8 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -750,6 +750,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
seconds. Defaults to 10*60 = 10mins. A value of 0
disables the blank timer.
+ core_ctl_disable_cpumask= [SMP]
+ Exempt the CPUs from being managed by core_ctl.
+ core_ctl operates on a cluster basis. So all the
+ CPUs in a given cluster must be specified to disable
+ core_ctl for that cluster.
+
coredump_filter=
[KNL] Change the default value for
/proc/<pid>/coredump_filter.
@@ -1265,6 +1271,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
When zero, profiling data is discarded and associated
debugfs files are removed at module unload time.
+ goldfish [X86] Enable the goldfish android emulator platform.
+ Don't use this when you are not running on the
+ android emulator
+
gpt [EFI] Forces disk with valid GPT signature but
invalid Protective MBR to be treated as GPT. If the
primary GPT is corrupted, it enables the backup/alternate
diff --git a/Documentation/mic/Makefile b/Documentation/mic/Makefile
deleted file mode 100644
index a191d453badf..000000000000
--- a/Documentation/mic/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-subdir-y := mpssd
diff --git a/Documentation/mic/mpssd/Makefile b/Documentation/mic/mpssd/Makefile
deleted file mode 100644
index 06871b0c08a6..000000000000
--- a/Documentation/mic/mpssd/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-ifndef CROSS_COMPILE
-# List of programs to build
-hostprogs-$(CONFIG_X86_64) := mpssd
-
-mpssd-objs := mpssd.o sysfs.o
-
-# Tell kbuild to always build the programs
-always := $(hostprogs-y)
-
-HOSTCFLAGS += -I$(objtree)/usr/include -I$(srctree)/tools/include
-
-ifdef DEBUG
-HOSTCFLAGS += -DDEBUG=$(DEBUG)
-endif
-
-HOSTLOADLIBES_mpssd := -lpthread
-
-install:
- install mpssd /usr/sbin/mpssd
- install micctrl /usr/sbin/micctrl
-endif
diff --git a/Documentation/networking/rmnet.txt b/Documentation/networking/rmnet.txt
new file mode 100644
index 000000000000..73a2c06dbc9e
--- /dev/null
+++ b/Documentation/networking/rmnet.txt
@@ -0,0 +1,82 @@
+1. Introduction
+
+rmnet driver is used for supporting the Multiplexing and aggregation
+Protocol (MAP). This protocol is used by all recent chipsets using Qualcomm
+Technologies, Inc. modems.
+
+This driver can be used to register onto any physical network device in
+IP mode. Physical transports include USB, HSIC, PCIe and IP accelerator.
+
+Multiplexing allows for creation of logical netdevices (rmnet devices) to
+handle multiple private data networks (PDN) like a default internet, tethering,
+multimedia messaging service (MMS) or IP media subsystem (IMS). Hardware sends
+packets with MAP headers to rmnet. Based on the multiplexer id, rmnet
+routes to the appropriate PDN after removing the MAP header.
+
+Aggregation is required to achieve high data rates. This involves hardware
+sending aggregated bunch of MAP frames. rmnet driver will de-aggregate
+these MAP frames and send them to appropriate PDN's.
+
+2. Packet format
+
+a. MAP packet (data / control)
+
+MAP header has the same endianness of the IP packet.
+
+Packet format -
+
+Bit 0 1 2-7 8 - 15 16 - 31
+Function Command / Data Reserved Pad Multiplexer ID Payload length
+Bit 32 - x
+Function Raw Bytes
+
+Command (1)/ Data (0) bit value is to indicate if the packet is a MAP command
+or data packet. Control packet is used for transport level flow control. Data
+packets are standard IP packets.
+
+Reserved bits are usually zeroed out and to be ignored by receiver.
+
+Padding is number of bytes to be added for 4 byte alignment if required by
+hardware.
+
+Multiplexer ID is to indicate the PDN on which data has to be sent.
+
+Payload length includes the padding length but does not include MAP header
+length.
+
+b. MAP packet (command specific)
+
+Bit 0 1 2-7 8 - 15 16 - 31
+Function Command Reserved Pad Multiplexer ID Payload length
+Bit 32 - 39 40 - 45 46 - 47 48 - 63
+Function Command name Reserved Command Type Reserved
+Bit 64 - 95
+Function Transaction ID
+Bit 96 - 127
+Function Command data
+
+Command 1 indicates disabling flow while 2 is enabling flow
+
+Command types -
+0 for MAP command request
+1 is to acknowledge the receipt of a command
+2 is for unsupported commands
+3 is for error during processing of commands
+
+c. Aggregation
+
+Aggregation is multiple MAP packets (can be data or command) delivered to
+rmnet in a single linear skb. rmnet will process the individual
+packets and either ACK the MAP command or deliver the IP packet to the
+network stack as needed
+
+MAP header|IP Packet|Optional padding|MAP header|IP Packet|Optional padding....
+MAP header|IP Packet|Optional padding|MAP header|Command Packet|Optional pad...
+
+3. Userspace configuration
+
+rmnet userspace configuration is done through netlink library librmnetctl
+and command line utility rmnetcli. Utility is hosted in codeaurora forum git
+
+https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/\
+dataservices/tree/rmnetctl
diff --git a/Makefile b/Makefile
index 3c5b81204c95..3a8de39e5823 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 4
PATCHLEVEL = 4
-SUBLEVEL = 49
+SUBLEVEL = 55
EXTRAVERSION =
NAME = Blurry Fish Butt
diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
index e74df327cdd3..20618a897c99 100644
--- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
@@ -122,6 +122,8 @@
uart1: serial@f8020000 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1_default>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
status = "okay";
};
diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained.dts b/arch/arm/boot/dts/at91-sama5d4_xplained.dts
index da84e65b56ef..e27024cdf48b 100644
--- a/arch/arm/boot/dts/at91-sama5d4_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d4_xplained.dts
@@ -110,6 +110,8 @@
};
usart3: serial@fc00c000 {
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
status = "okay";
};
diff --git a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi
index b7a3d3f5cba5..e74aded8c9e3 100644
--- a/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi
+++ b/arch/arm/boot/dts/qcom/apq8096-auto-dragonboard.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -624,11 +624,13 @@
"msm-pcm-routing", "msm-compr-dsp",
"msm-pcm-loopback.1";
asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>,
- <&dai_mi2s>, <&dai_mi2s_quat>,
+ <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>,
<&afe_pcm_rx>, <&afe_pcm_tx>,
<&afe_proxy_rx>, <&afe_proxy_tx>,
<&incall_record_rx>, <&incall_record_tx>,
<&incall_music_rx>, <&incall_music2_rx>,
+ <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>,
+ <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>,
<&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>,
<&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>,
<&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>,
@@ -638,12 +640,14 @@
<&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>,
<&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>;
asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
- "msm-dai-q6-hdmi.8",
+ "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.1",
"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
"msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
"msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
"msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
"msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+ "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883",
+ "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887",
"msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898",
"msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902",
"msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899",
@@ -668,6 +672,16 @@
};
qcom,msm-dai-mi2s {
+ dai_mi2s_sec: qcom,msm-dai-q6-mi2s-sec {
+ qcom,msm-mi2s-rx-lines = <2>;
+ qcom,msm-mi2s-tx-lines = <1>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sec_mi2s_active &sec_mi2s_sd0_active
+ &sec_mi2s_sd1_active>;
+ pinctrl-1 = <&sec_mi2s_sleep &sec_mi2s_sd0_sleep
+ &sec_mi2s_sd1_sleep>;
+ };
+
dai_mi2s_quat: qcom,msm-dai-q6-mi2s-quat {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&quat_mi2s_active &quat_mi2s_sd0_active>;
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
index 69f24bbfc3c0..8d867bb697be 100644
--- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
+++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi
@@ -216,6 +216,8 @@
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,mdss-pan-physical-width-dimension = <74>;
+ qcom,mdss-pan-physical-height-dimension = <131>;
qcom,config-select = <&dsi_dual_nt35597_truly_cmd_config0>;
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
index ab6266e9e6b8..1a572f97c840 100644
--- a/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
+++ b/arch/arm/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi
@@ -202,6 +202,8 @@
qcom,mdss-dsi-mdp-trigger = "none";
qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 50>;
qcom,mdss-dsi-tx-eot-append;
+ qcom,mdss-pan-physical-width-dimension = <74>;
+ qcom,mdss-pan-physical-height-dimension = <131>;
qcom,config-select = <&dsi_dual_nt35597_truly_video_config0>;
diff --git a/arch/arm/boot/dts/qcom/msm-audio.dtsi b/arch/arm/boot/dts/qcom/msm-audio.dtsi
index 42cf30c789d9..d450f43f8c22 100644
--- a/arch/arm/boot/dts/qcom/msm-audio.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-audio.dtsi
@@ -931,6 +931,8 @@
clocks = <&clock_rpmcc RPM_DIV_CLK1>;
qcom,node_has_rpm_clock;
#clock-cells = <1>;
+ qcom,codec-mclk-clk-freq = <11289600>;
+ qcom,mclk-clk-reg = <0x15020018 0x0>;
pinctrl-names = "sleep", "active";
pinctrl-0 = <&lpi_mclk0_sleep>;
pinctrl-1 = <&lpi_mclk0_active>;
diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
index bcdbc4ed7c55..7f386957d555 100644
--- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
@@ -397,7 +397,7 @@
interrupts = <0x3 0xec 0x1 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "sc-irq";
- qcom,force-module-reenable;
+ qcom,pmic-revid = <&pm660l_revid>;
lcdb_ldo_vreg: ldo {
label = "ldo";
diff --git a/arch/arm/boot/dts/qcom/msm-smb138x.dtsi b/arch/arm/boot/dts/qcom/msm-smb138x.dtsi
index ea4f05069aab..df7d30210c19 100644
--- a/arch/arm/boot/dts/qcom/msm-smb138x.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-smb138x.dtsi
@@ -128,3 +128,10 @@
};
};
};
+
+&smb138x_parallel_slave {
+ smb138x_vbus: qcom,smb138x-vbus {
+ status = "disabled";
+ regulator-name = "smb138x-vbus";
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
index 8d7309e96c0f..d007e8bcfc33 100644
--- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -607,11 +607,13 @@
"msm-pcm-routing", "msm-compr-dsp",
"msm-pcm-loopback.1";
asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>,
- <&dai_mi2s>, <&dai_mi2s_quat>,
+ <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>,
<&afe_pcm_rx>, <&afe_pcm_tx>,
<&afe_proxy_rx>, <&afe_proxy_tx>,
<&incall_record_rx>, <&incall_record_tx>,
<&incall_music_rx>, <&incall_music2_rx>,
+ <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>,
+ <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>,
<&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>,
<&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>,
<&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>,
@@ -621,12 +623,14 @@
<&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>,
<&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>;
asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
- "msm-dai-q6-hdmi.8",
+ "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.1",
"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
"msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
"msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
"msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
"msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+ "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883",
+ "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887",
"msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898",
"msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902",
"msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899",
@@ -651,6 +655,8 @@
qcom,msm-dai-mi2s {
dai_mi2s_sec: qcom,msm-dai-q6-mi2s-sec {
+ qcom,msm-mi2s-rx-lines = <2>;
+ qcom,msm-mi2s-tx-lines = <1>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&sec_mi2s_active &sec_mi2s_sd0_active
&sec_mi2s_sd1_active>;
diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
index 84b4efd71253..97036ae144ae 100644
--- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -628,11 +628,13 @@
"msm-pcm-routing", "msm-compr-dsp",
"msm-pcm-loopback.1";
asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>,
- <&dai_mi2s>, <&dai_mi2s_quat>,
+ <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>,
<&afe_pcm_rx>, <&afe_pcm_tx>,
<&afe_proxy_rx>, <&afe_proxy_tx>,
<&incall_record_rx>, <&incall_record_tx>,
<&incall_music_rx>, <&incall_music2_rx>,
+ <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>,
+ <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>,
<&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>,
<&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>,
<&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>,
@@ -642,12 +644,14 @@
<&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>,
<&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>;
asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
- "msm-dai-q6-hdmi.8",
+ "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.1",
"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
"msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
"msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
"msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
"msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+ "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883",
+ "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887",
"msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898",
"msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902",
"msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899",
@@ -688,6 +692,16 @@
};
qcom,msm-dai-mi2s {
+ dai_mi2s_sec: qcom,msm-dai-q6-mi2s-sec {
+ qcom,msm-mi2s-rx-lines = <2>;
+ qcom,msm-mi2s-tx-lines = <1>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sec_mi2s_active &sec_mi2s_sd0_active
+ &sec_mi2s_sd1_active>;
+ pinctrl-1 = <&sec_mi2s_sleep &sec_mi2s_sd0_sleep
+ &sec_mi2s_sd1_sleep>;
+ };
+
dai_mi2s_quat: qcom,msm-dai-q6-mi2s-quat {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&quat_mi2s_active &quat_mi2s_sd0_active>;
diff --git a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi
index 7370422d737e..b6e6fb4193b4 100644
--- a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -533,11 +533,13 @@
"msm-pcm-routing", "msm-compr-dsp",
"msm-pcm-loopback.1";
asoc-cpu = <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, <&dai_hdmi>,
- <&dai_mi2s>, <&dai_mi2s_quat>,
+ <&dai_mi2s_sec>, <&dai_mi2s>, <&dai_mi2s_quat>,
<&afe_pcm_rx>, <&afe_pcm_tx>,
<&afe_proxy_rx>, <&afe_proxy_tx>,
<&incall_record_rx>, <&incall_record_tx>,
<&incall_music_rx>, <&incall_music2_rx>,
+ <&dai_sec_tdm_tx_0>, <&dai_sec_tdm_tx_1>,
+ <&dai_sec_tdm_tx_2>, <&dai_sec_tdm_tx_3>,
<&dai_tert_tdm_rx_0>, <&dai_tert_tdm_rx_1>,
<&dai_tert_tdm_rx_2>, <&dai_tert_tdm_rx_3>,
<&dai_tert_tdm_tx_0>, <&dai_tert_tdm_tx_1>,
@@ -547,12 +549,14 @@
<&dai_quat_tdm_tx_0>, <&dai_quat_tdm_tx_1>,
<&dai_quat_tdm_tx_2>, <&dai_quat_tdm_tx_3>;
asoc-cpu-names = "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2",
- "msm-dai-q6-hdmi.8",
+ "msm-dai-q6-hdmi.8", "msm-dai-q6-mi2s.1",
"msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
"msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
"msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
"msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
"msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770",
+ "msm-dai-q6-tdm.36881", "msm-dai-q6-tdm.36883",
+ "msm-dai-q6-tdm.36885", "msm-dai-q6-tdm.36887",
"msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36898",
"msm-dai-q6-tdm.36900", "msm-dai-q6-tdm.36902",
"msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36899",
@@ -571,6 +575,16 @@
};
qcom,msm-dai-mi2s {
+ dai_mi2s_sec: qcom,msm-dai-q6-mi2s-sec {
+ qcom,msm-mi2s-rx-lines = <2>;
+ qcom,msm-mi2s-tx-lines = <1>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&sec_mi2s_active &sec_mi2s_sd0_active
+ &sec_mi2s_sd1_active>;
+ pinctrl-1 = <&sec_mi2s_sleep &sec_mi2s_sd0_sleep
+ &sec_mi2s_sd1_sleep>;
+ };
+
dai_mi2s_quat: qcom,msm-dai-q6-mi2s-quat {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&quat_mi2s_active &quat_mi2s_sd0_active>;
diff --git a/arch/arm/boot/dts/qcom/msm8996-v3.dtsi b/arch/arm/boot/dts/qcom/msm8996-v3.dtsi
index c30e19eacc69..7e5fa8a495c9 100644
--- a/arch/arm/boot/dts/qcom/msm8996-v3.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996-v3.dtsi
@@ -73,6 +73,23 @@
< 315000000 4 >,
< 401800000 5 >,
< 510000000 5 >;
+
+ qcom,gfxfreq-speedbin2 =
+ < 0 0 0 >,
+ < 133000000 2 4 >,
+ < 214000000 3 4 >,
+ < 315000000 4 4 >,
+ < 401800000 5 5 >,
+ < 510000000 6 5 >,
+ < 560000000 7 7 >;
+ qcom,gfxfreq-mx-speedbin2 =
+ < 0 0 >,
+ < 133000000 4 >,
+ < 214000000 4 >,
+ < 315000000 4 >,
+ < 401800000 5 >,
+ < 510000000 5 >,
+ < 560000000 7 >;
};
&gdsc_gpu_gx {
@@ -416,6 +433,23 @@
< 1190400000 11 >,
< 1228800000 12 >,
< 1363200000 13 >;
+ qcom,pwrcl-speedbin2-v0 =
+ < 0 0 >,
+ < 307200000 1 >,
+ < 422400000 2 >,
+ < 480000000 3 >,
+ < 556800000 4 >,
+ < 652800000 5 >,
+ < 729600000 6 >,
+ < 844800000 7 >,
+ < 960000000 8 >,
+ < 1036800000 9 >,
+ < 1113600000 10 >,
+ < 1190400000 11 >,
+ < 1228800000 12 >,
+ < 1324800000 13 >,
+ < 1401600000 14 >,
+ < 1497600000 15 >;
qcom,perfcl-speedbin0-v0 =
< 0 0 >,
< 307200000 1 >,
@@ -466,6 +500,30 @@
< 1708800000 19 >,
< 1785600000 20 >,
< 1804800000 21 >;
+ qcom,perfcl-speedbin2-v0 =
+ < 0 0 >,
+ < 307200000 1 >,
+ < 403200000 2 >,
+ < 480000000 3 >,
+ < 556800000 4 >,
+ < 652800000 5 >,
+ < 729600000 6 >,
+ < 806400000 7 >,
+ < 883200000 8 >,
+ < 940800000 9 >,
+ < 1036800000 10 >,
+ < 1113600000 11 >,
+ < 1190400000 12 >,
+ < 1248000000 13 >,
+ < 1324800000 14 >,
+ < 1401600000 15 >,
+ < 1478400000 16 >,
+ < 1555200000 17 >,
+ < 1632000000 18 >,
+ < 1708800000 19 >,
+ < 1785600000 20 >,
+ < 1804800000 21 >,
+ < 1900800000 22 >;
qcom,cbf-speedbin0-v0 =
< 0 0 >,
< 307200000 1 >,
@@ -504,6 +562,23 @@
< 1190400000 13 >,
< 1228800000 14 >,
< 1305600000 15 >;
+ qcom,cbf-speedbin2-v0 =
+ < 0 0 >,
+ < 307200000 1 >,
+ < 384000000 2 >,
+ < 460800000 3 >,
+ < 537600000 4 >,
+ < 595200000 5 >,
+ < 672000000 6 >,
+ < 748800000 7 >,
+ < 825600000 8 >,
+ < 902400000 9 >,
+ < 979200000 10 >,
+ < 1056000000 11 >,
+ < 1132800000 12 >,
+ < 1190400000 13 >,
+ < 1228800000 14 >,
+ < 1305600000 15 >;
};
&msm_cpufreq {
diff --git a/arch/arm/boot/dts/qcom/msm8996.dtsi b/arch/arm/boot/dts/qcom/msm8996.dtsi
index 49eafeaa5d70..7c0f8e3c331f 100644
--- a/arch/arm/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996.dtsi
@@ -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
@@ -3337,6 +3337,57 @@
};
};
+ qcom,msm-dai-tdm-sec-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37137>;
+ qcom,msm-cpudai-tdm-group-num-ports = <4>;
+ qcom,msm-cpudai-tdm-group-port-id = <36881 36883 36885 36887>;
+ qcom,msm-cpudai-tdm-clk-rate = <0>;
+ dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36881>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+
+ dai_sec_tdm_tx_1: qcom,msm-dai-q6-tdm-sec-tx-1 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36883>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+
+ dai_sec_tdm_tx_2: qcom,msm-dai-q6-tdm-sec-tx-2 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36885>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+
+ dai_sec_tdm_tx_3: qcom,msm-dai-q6-tdm-sec-tx-3 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36887>;
+ qcom,msm-cpudai-tdm-sync-mode = <1>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
qcom,msm-dai-tdm-tert-rx {
compatible = "qcom,msm-dai-tdm";
qcom,msm-cpudai-tdm-group-id = <37152>;
diff --git a/arch/arm/boot/dts/qcom/msm8996pro.dtsi b/arch/arm/boot/dts/qcom/msm8996pro.dtsi
index 094a4cfbabdc..28577dc6d72f 100644
--- a/arch/arm/boot/dts/qcom/msm8996pro.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8996pro.dtsi
@@ -956,7 +956,8 @@
< 1363200000 15 >,
< 1440000000 16 >,
< 1516800000 17 >,
- < 1593600000 18 >;
+ < 1593600000 18 >,
+ < 1996800000 20 >;
qcom,perfcl-speedbin0-v0 =
< 0 0 >,
< 307200000 1 >,
@@ -1244,6 +1245,9 @@
&soc {
qcom,msm-thermal {
+ qcom,poll-ms = <50>;
+ qcom,limit-temp = <80>;
+ qcom,core-limit-temp = <90>;
qcom,vdd-gfx-rstr{
qcom,levels = <6 8 9>; /* Nominal, Turbo, Turbo_L1 */
};
diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi
index 707eca4e9ddd..d5c8900f6e67 100644
--- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-cdp.dtsi
@@ -95,6 +95,7 @@
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_tof_active>;
pinctrl-1 = <&cam_tof_suspend>;
+ stm,irq-gpio = <&tlmm 26 0x2008>;
gpios = <&tlmm 126 0>;
qcom,gpio-req-tbl-num = <0>;
qcom,gpio-req-tbl-flags = <0>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi
index 17dcfb560b73..2ed0f2250de5 100644
--- a/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-camera-sensor-mtp.dtsi
@@ -79,6 +79,7 @@
pinctrl-names = "cam_default", "cam_suspend";
pinctrl-0 = <&cam_tof_active>;
pinctrl-1 = <&cam_tof_suspend>;
+ stm,irq-gpio = <&tlmm 26 0x2008>;
gpios = <&tlmm 126 0>;
qcom,gpio-req-tbl-num = <0>;
qcom,gpio-req-tbl-flags = <0>;
diff --git a/arch/arm/boot/dts/qcom/msm8998-camera.dtsi b/arch/arm/boot/dts/qcom/msm8998-camera.dtsi
index e0ba982d7932..f87444465a68 100644
--- a/arch/arm/boot/dts/qcom/msm8998-camera.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-camera.dtsi
@@ -493,11 +493,11 @@
<&clock_mmss clk_mmss_camss_csi1_clk>,
<&clock_mmss clk_mmss_camss_csi2_clk>,
<&clock_mmss clk_mmss_camss_csi3_clk>,
- <&clock_mmss clk_mmss_camss_vfe0_clk>,
<&clock_mmss clk_vfe0_clk_src>,
+ <&clock_mmss clk_mmss_camss_vfe0_clk>,
<&clock_mmss clk_mmss_camss_csi_vfe0_clk>,
- <&clock_mmss clk_mmss_camss_vfe1_clk>,
<&clock_mmss clk_vfe1_clk_src>,
+ <&clock_mmss clk_mmss_camss_vfe1_clk>,
<&clock_mmss clk_mmss_camss_csi_vfe1_clk>;
clock-names = "mmssnoc_axi", "mnoc_ahb_clk",
"camss_ahb_clk",
@@ -510,10 +510,12 @@
"csi2_pix_clk", "csi3_pix_clk",
"camss_csi0_clk", "camss_csi1_clk",
"camss_csi2_clk", "camss_csi3_clk",
+ "vfe0_clk_src",
"camss_vfe_vfe0_clk",
- "vfe0_clk_src", "camss_csi_vfe0_clk",
+ "camss_csi_vfe0_clk",
+ "vfe1_clk_src",
"camss_vfe_vfe1_clk",
- "vfe1_clk_src", "camss_csi_vfe1_clk";
+ "camss_csi_vfe1_clk";
qcom,clock-rates = <0 0 0 0 0
0 0 0 0
0 0 0 0
@@ -532,10 +534,10 @@
"NO_SET_RATE", "NO_SET_RATE",
"NO_SET_RATE", "NO_SET_RATE",
"NO_SET_RATE", "NO_SET_RATE",
- "NO_SET_RATE",
- "INIT_RATE", "NO_SET_RATE",
- "NO_SET_RATE",
- "INIT_RATE", "NO_SET_RATE";
+ "INIT_RATE",
+ "NO_SET_RATE", "NO_SET_RATE",
+ "INIT_RATE",
+ "NO_SET_RATE", "NO_SET_RATE";
status = "ok";
};
@@ -557,23 +559,23 @@
<&clock_mmss clk_mmss_bimc_smmu_axi_clk>,
<&clock_mmss clk_mmss_camss_ahb_clk>,
<&clock_mmss clk_mmss_camss_top_ahb_clk>,
+ <&clock_mmss clk_vfe0_clk_src>,
<&clock_mmss clk_mmss_camss_vfe0_clk>,
<&clock_mmss clk_mmss_camss_vfe0_stream_clk>,
<&clock_mmss clk_mmss_camss_vfe0_ahb_clk>,
<&clock_mmss clk_mmss_camss_vfe_vbif_ahb_clk>,
<&clock_mmss clk_mmss_camss_vfe_vbif_axi_clk>,
- <&clock_mmss clk_vfe0_clk_src>,
<&clock_mmss clk_mmss_camss_csi_vfe0_clk>;
clock-names = "mmssnoc_axi", "mnoc_ahb_clk",
"bimc_smmu_ahb_clk", "bimc_smmu_axi_clk",
- "camss_ahb_clk", "camss_top_ahb_clk",
+ "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src",
"camss_vfe_clk", "camss_vfe_stream_clk",
"camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk",
- "camss_vfe_vbif_axi_clk", "vfe_clk_src",
+ "camss_vfe_vbif_axi_clk",
"camss_csi_vfe_clk";
- qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 480000000 0
- 0 0 0 0 0 0 0 0 0 0 0 576000000 0
- 0 0 0 0 0 0 0 0 0 0 0 600000000 0>;
+ qcom,clock-rates = <0 0 0 0 0 0 480000000 0 0 0 0 0 0
+ 0 0 0 0 0 0 576000000 0 0 0 0 0 0
+ 0 0 0 0 0 0 600000000 0 0 0 0 0 0>;
status = "ok";
qos-entries = <8>;
qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418
@@ -637,23 +639,23 @@
<&clock_mmss clk_mmss_bimc_smmu_axi_clk>,
<&clock_mmss clk_mmss_camss_ahb_clk>,
<&clock_mmss clk_mmss_camss_top_ahb_clk>,
+ <&clock_mmss clk_vfe1_clk_src>,
<&clock_mmss clk_mmss_camss_vfe1_clk>,
<&clock_mmss clk_mmss_camss_vfe1_stream_clk>,
<&clock_mmss clk_mmss_camss_vfe1_ahb_clk>,
<&clock_mmss clk_mmss_camss_vfe_vbif_ahb_clk>,
<&clock_mmss clk_mmss_camss_vfe_vbif_axi_clk>,
- <&clock_mmss clk_vfe1_clk_src>,
<&clock_mmss clk_mmss_camss_csi_vfe1_clk>;
clock-names = "mmssnoc_axi", "mnoc_ahb_clk",
"bimc_smmu_ahb_clk", "bimc_smmu_axi_clk",
- "camss_ahb_clk", "camss_top_ahb_clk",
+ "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src",
"camss_vfe_clk", "camss_vfe_stream_clk",
"camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk",
- "camss_vfe_vbif_axi_clk", "vfe_clk_src",
+ "camss_vfe_vbif_axi_clk",
"camss_csi_vfe_clk";
- qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 480000000 0
- 0 0 0 0 0 0 0 0 0 0 0 576000000 0
- 0 0 0 0 0 0 0 0 0 0 0 600000000 0>;
+ qcom,clock-rates = <0 0 0 0 0 0 480000000 0 0 0 0 0 0
+ 0 0 0 0 0 0 576000000 0 0 0 0 0 0
+ 0 0 0 0 0 0 600000000 0 0 0 0 0 0>;
status = "ok";
qos-entries = <8>;
qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418
diff --git a/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi b/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
index 518ad33c63ea..045cdda09d18 100644
--- a/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998-regulator.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -409,6 +409,7 @@
pm8998_l24: regulator-l24 {
regulator-min-microvolt = <3088000>;
regulator-max-microvolt = <3088000>;
+ parent-supply = <&pm8998_l12>;
status = "okay";
};
};
diff --git a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi
index 82b9b2cf4de8..8b226586ca7b 100644
--- a/arch/arm/boot/dts/qcom/sdm630-camera.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-camera.dtsi
@@ -451,11 +451,11 @@
<&clock_mmss MMSS_CAMSS_CSI1_CLK>,
<&clock_mmss MMSS_CAMSS_CSI2_CLK>,
<&clock_mmss MMSS_CAMSS_CSI3_CLK>,
- <&clock_mmss MMSS_CAMSS_VFE0_CLK>,
<&clock_mmss VFE0_CLK_SRC>,
+ <&clock_mmss MMSS_CAMSS_VFE0_CLK>,
<&clock_mmss MMSS_CAMSS_CSI_VFE0_CLK>,
- <&clock_mmss MMSS_CAMSS_VFE1_CLK>,
<&clock_mmss VFE1_CLK_SRC>,
+ <&clock_mmss MMSS_CAMSS_VFE1_CLK>,
<&clock_mmss MMSS_CAMSS_CSI_VFE1_CLK>;
clock-names = "mmssnoc_axi", "mnoc_ahb_clk",
"camss_ahb_clk",
@@ -468,10 +468,12 @@
"csi2_pix_clk", "csi3_pix_clk",
"camss_csi0_clk", "camss_csi1_clk",
"camss_csi2_clk", "camss_csi3_clk",
+ "vfe0_clk_src",
"camss_vfe_vfe0_clk",
- "vfe0_clk_src", "camss_csi_vfe0_clk",
+ "camss_csi_vfe0_clk",
+ "vfe1_clk_src",
"camss_vfe_vfe1_clk",
- "vfe1_clk_src", "camss_csi_vfe1_clk";
+ "camss_csi_vfe1_clk";
qcom,clock-rates = <0 0 0 0 0
0 0 0 0
0 0 0 0
@@ -490,10 +492,10 @@
"NO_SET_RATE", "NO_SET_RATE",
"NO_SET_RATE", "NO_SET_RATE",
"NO_SET_RATE", "NO_SET_RATE",
- "NO_SET_RATE",
- "INIT_RATE", "NO_SET_RATE",
- "NO_SET_RATE",
- "INIT_RATE", "NO_SET_RATE";
+ "INIT_RATE",
+ "NO_SET_RATE", "NO_SET_RATE",
+ "INIT_RATE",
+ "NO_SET_RATE", "NO_SET_RATE";
status = "ok";
};
@@ -516,23 +518,23 @@
<&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>,
<&clock_mmss MMSS_CAMSS_AHB_CLK>,
<&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>,
+ <&clock_mmss VFE0_CLK_SRC>,
<&clock_mmss MMSS_CAMSS_VFE0_CLK>,
<&clock_mmss MMSS_CAMSS_VFE0_STREAM_CLK>,
<&clock_mmss MMSS_CAMSS_VFE0_AHB_CLK>,
<&clock_mmss MMSS_CAMSS_VFE_VBIF_AHB_CLK>,
<&clock_mmss MMSS_CAMSS_VFE_VBIF_AXI_CLK>,
- <&clock_mmss VFE0_CLK_SRC>,
<&clock_mmss MMSS_CAMSS_CSI_VFE0_CLK>;
clock-names = "mmssnoc_axi", "mnoc_ahb_clk",
"bimc_smmu_ahb_clk", "bimc_smmu_axi_clk",
- "camss_ahb_clk", "camss_top_ahb_clk",
+ "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src",
"camss_vfe_clk", "camss_vfe_stream_clk",
"camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk",
- "camss_vfe_vbif_axi_clk", "vfe_clk_src",
+ "camss_vfe_vbif_axi_clk",
"camss_csi_vfe_clk";
- qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 404000000 0
- 0 0 0 0 0 0 0 0 0 0 0 480000000 0
- 0 0 0 0 0 0 0 0 0 0 0 576000000 0>;
+ qcom,clock-rates = <0 0 0 0 0 0 404000000 0 0 0 0 0 0
+ 0 0 0 0 0 0 480000000 0 0 0 0 0 0
+ 0 0 0 0 0 0 576000000 0 0 0 0 0 0>;
status = "ok";
qos-entries = <8>;
qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418
@@ -597,23 +599,23 @@
<&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>,
<&clock_mmss MMSS_CAMSS_AHB_CLK>,
<&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>,
+ <&clock_mmss VFE1_CLK_SRC>,
<&clock_mmss MMSS_CAMSS_VFE1_CLK>,
<&clock_mmss MMSS_CAMSS_VFE1_STREAM_CLK>,
<&clock_mmss MMSS_CAMSS_VFE1_AHB_CLK>,
<&clock_mmss MMSS_CAMSS_VFE_VBIF_AHB_CLK>,
<&clock_mmss MMSS_CAMSS_VFE_VBIF_AXI_CLK>,
- <&clock_mmss VFE1_CLK_SRC>,
<&clock_mmss MMSS_CAMSS_CSI_VFE1_CLK>;
clock-names = "mmssnoc_axi", "mnoc_ahb_clk",
"bimc_smmu_ahb_clk", "bimc_smmu_axi_clk",
- "camss_ahb_clk", "camss_top_ahb_clk",
+ "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src",
"camss_vfe_clk", "camss_vfe_stream_clk",
"camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk",
- "camss_vfe_vbif_axi_clk", "vfe_clk_src",
+ "camss_vfe_vbif_axi_clk",
"camss_csi_vfe_clk";
- qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 404000000 0
- 0 0 0 0 0 0 0 0 0 0 0 480000000 0
- 0 0 0 0 0 0 0 0 0 0 0 576000000 0>;
+ qcom,clock-rates = <0 0 0 0 0 0 404000000 0 0 0 0 0 0
+ 0 0 0 0 0 0 480000000 0 0 0 0 0 0
+ 0 0 0 0 0 0 576000000 0 0 0 0 0 0>;
status = "ok";
qos-entries = <8>;
qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418
diff --git a/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi
index 0dd2d206ddd5..e0d51db067c9 100644
--- a/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-gpu.dtsi
@@ -114,8 +114,8 @@
vdd-supply = <&gdsc_gpu_gx>;
/* CPU latency parameter */
- qcom,pm-qos-active-latency = <349>;
- qcom,pm-qos-wakeup-latency = <349>;
+ qcom,pm-qos-active-latency = <424>;
+ qcom,pm-qos-wakeup-latency = <424>;
/* Quirks */
qcom,gpu-quirk-dp2clockgating-disable;
diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi
index 43a01094662a..81e0c6930bf3 100644
--- a/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-mdss-panels.dtsi
@@ -15,6 +15,7 @@
#include "dsi-panel-nt35695b-truly-fhd-cmd.dtsi"
#include "dsi-panel-truly-1080p-cmd.dtsi"
#include "dsi-panel-truly-1080p-video.dtsi"
+#include "dsi-panel-rm67195-amoled-fhd-cmd.dtsi"
&soc {
dsi_panel_pwr_supply: dsi_panel_pwr_supply {
@@ -49,6 +50,57 @@
qcom,supply-post-on-sleep = <10>;
};
};
+
+ dsi_panel_pwr_supply_labibb_amoled:
+ dsi_panel_pwr_supply_labibb_amoled {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,panel-supply-entry@0 {
+ reg = <0>;
+ qcom,supply-name = "wqhd-vddio";
+ qcom,supply-min-voltage = <1800000>;
+ qcom,supply-max-voltage = <1950000>;
+ qcom,supply-enable-load = <32000>;
+ qcom,supply-disable-load = <80>;
+ };
+
+ qcom,panel-supply-entry@1 {
+ reg = <1>;
+ qcom,supply-name = "vdda-3p3";
+ qcom,supply-min-voltage = <3300000>;
+ qcom,supply-max-voltage = <3300000>;
+ qcom,supply-enable-load = <13200>;
+ qcom,supply-disable-load = <80>;
+ };
+
+ qcom,panel-supply-entry@2 {
+ reg = <2>;
+ qcom,supply-name = "lab";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6100000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@3 {
+ reg = <3>;
+ qcom,supply-name = "ibb";
+ qcom,supply-min-voltage = <4000000>;
+ qcom,supply-max-voltage = <6300000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@4 {
+ reg = <4>;
+ qcom,supply-name = "oledb";
+ qcom,supply-min-voltage = <5000000>;
+ qcom,supply-max-voltage = <8100000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+ };
};
&dsi_nt35695b_truly_fhd_video {
@@ -98,3 +150,13 @@
qcom,esd-check-enabled;
qcom,mdss-dsi-panel-status-check-mode = "bta_check";
};
+
+&dsi_rm67195_amoled_fhd_cmd {
+ qcom,mdss-dsi-panel-timings-phy-v2 = [23 1e 07 08 05 03 04 a0
+ 23 1e 07 08 05 03 04 a0
+ 23 1e 07 08 05 03 04 a0
+ 23 1e 07 08 05 03 04 a0
+ 23 19 07 08 05 03 04 a0];
+ qcom,mdss-dsi-t-clk-post = <0x0d>;
+ qcom,mdss-dsi-t-clk-pre = <0x2d>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi
index 9c34a60e7aaa..9ac76f7e2f6e 100644
--- a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi
@@ -347,6 +347,7 @@
qcom,timing-db-mode;
wqhd-vddio-supply = <&pm660_l11>;
+ vdda-3p3-supply = <&pm660l_l6>;
lab-supply = <&lcdb_ldo_vreg>;
ibb-supply = <&lcdb_ncp_vreg>;
qcom,mdss-mdp = <&mdss_mdp>;
@@ -527,6 +528,19 @@
qcom,mdss-default-ot-rd-limit = <32>;
qcom,mdss-default-ot-wr-limit = <32>;
+
+ qcom,sde-reg-bus {
+ /* Reg Bus Scale Settings */
+ qcom,msm-bus,name = "mdss_rot_reg";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,vectors-KBps =
+ <1 590 0 0>,
+ <1 590 0 76800>,
+ <1 590 0 160000>,
+ <1 590 0 320000>;
+ };
};
};
diff --git a/arch/arm/boot/dts/qcom/sdm630-pm.dtsi b/arch/arm/boot/dts/qcom/sdm630-pm.dtsi
index 093eadab0413..b8272b29aa89 100644
--- a/arch/arm/boot/dts/qcom/sdm630-pm.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-pm.dtsi
@@ -63,20 +63,20 @@
reg = <0>;
label = "system-active";
qcom,psci-mode = <0x0>;
- qcom,latency-us = <100>;
- qcom,ss-power = <725>;
- qcom,energy-overhead = <85000>;
- qcom,time-overhead = <120>;
+ qcom,latency-us = <50>;
+ qcom,ss-power = <240>;
+ qcom,energy-overhead = <61750>;
+ qcom,time-overhead = <7870>;
};
qcom,pm-cluster-level@1{ /* E3 */
reg = <1>;
label = "system-pc";
qcom,psci-mode = <0x3>;
- qcom,latency-us = <350>;
- qcom,ss-power = <530>;
- qcom,energy-overhead = <160000>;
- qcom,time-overhead = <550>;
+ qcom,latency-us = <4026>;
+ qcom,ss-power = <167>;
+ qcom,energy-overhead = <749982>;
+ qcom,time-overhead = <14773>;
qcom,min-child-idx = <3>;
qcom,is-reset;
qcom,notify-rpm;
@@ -96,19 +96,19 @@
reg = <0>;
label = "pwr-l2-active";
qcom,psci-mode = <0x1>;
- qcom,latency-us = <40>;
- qcom,ss-power = <740>;
- qcom,energy-overhead = <65000>;
- qcom,time-overhead = <85>;
+ qcom,latency-us = <51>;
+ qcom,ss-power = <198>;
+ qcom,energy-overhead = <83852>;
+ qcom,time-overhead = <91>;
};
qcom,pm-cluster-level@1{ /* D2D */
reg = <1>;
label = "pwr-l2-dynret";
qcom,psci-mode = <0x2>;
- qcom,latency-us = <60>;
- qcom,ss-power = <700>;
- qcom,energy-overhead = <85000>;
- qcom,time-overhead = <85>;
+ qcom,latency-us = <384>;
+ qcom,ss-power = <197>;
+ qcom,energy-overhead = <198413>;
+ qcom,time-overhead = <668>;
qcom,min-child-idx = <1>;
};
@@ -116,10 +116,10 @@
reg = <2>;
label = "pwr-l2-ret";
qcom,psci-mode = <0x3>;
- qcom,latency-us = <100>;
- qcom,ss-power = <640>;
- qcom,energy-overhead = <135000>;
- qcom,time-overhead = <85>;
+ qcom,latency-us = <423>;
+ qcom,ss-power = <193>;
+ qcom,energy-overhead = <218055>;
+ qcom,time-overhead = <761>;
qcom,min-child-idx = <2>;
};
@@ -127,10 +127,10 @@
reg = <3>;
label = "pwr-l2-pc";
qcom,psci-mode = <0x4>;
- qcom,latency-us = <700>;
- qcom,ss-power = <450>;
- qcom,energy-overhead = <210000>;
- qcom,time-overhead = <11500>;
+ qcom,latency-us = <1821>;
+ qcom,ss-power = <184>;
+ qcom,energy-overhead = <558835>;
+ qcom,time-overhead = <2336>;
qcom,min-child-idx = <2>;
qcom,is-reset;
};
@@ -145,30 +145,30 @@
reg = <0>;
qcom,spm-cpu-mode = "wfi";
qcom,psci-cpu-mode = <0x1>;
- qcom,latency-us = <20>;
- qcom,ss-power = <750>;
- qcom,energy-overhead = <32000>;
- qcom,time-overhead = <60>;
+ qcom,latency-us = <42>;
+ qcom,ss-power = <240>;
+ qcom,energy-overhead = <30562>;
+ qcom,time-overhead = <91>;
};
qcom,pm-cpu-level@1 { /* C2D */
reg = <1>;
qcom,psci-cpu-mode = <2>;
qcom,spm-cpu-mode = "ret";
- qcom,latency-us = <40>;
- qcom,ss-power = <730>;
- qcom,energy-overhead = <85500>;
- qcom,time-overhead = <110>;
+ qcom,latency-us = <90>;
+ qcom,ss-power = <213>;
+ qcom,energy-overhead = <79070>;
+ qcom,time-overhead = <253>;
};
qcom,pm-cpu-level@2 { /* C3 */
reg = <2>;
qcom,spm-cpu-mode = "pc";
qcom,psci-cpu-mode = <0x3>;
- qcom,latency-us = <80>;
- qcom,ss-power = <700>;
- qcom,energy-overhead = <126480>;
- qcom,time-overhead = <160>;
+ qcom,latency-us = <343>;
+ qcom,ss-power = <200>;
+ qcom,energy-overhead = <170215>;
+ qcom,time-overhead = <605>;
qcom,is-reset;
};
};
@@ -188,20 +188,20 @@
reg = <0>;
label = "perf-l2-active";
qcom,psci-mode = <0x1>;
- qcom,latency-us = <40>;
- qcom,ss-power = <740>;
- qcom,energy-overhead = <70000>;
- qcom,time-overhead = <80>;
+ qcom,latency-us = <51>;
+ qcom,ss-power = <287>;
+ qcom,energy-overhead = <61412>;
+ qcom,time-overhead = <89>;
};
qcom,pm-cluster-level@1{ /* D2D */
reg = <1>;
label = "perf-l2-dynret";
qcom,psci-mode = <2>;
- qcom,latency-us = <60>;
- qcom,ss-power = <700>;
- qcom,energy-overhead = <85000>;
- qcom,time-overhead = <85>;
+ qcom,latency-us = <329>;
+ qcom,ss-power = <284>;
+ qcom,energy-overhead = <206996>;
+ qcom,time-overhead = <601>;
qcom,min-child-idx = <1>;
};
@@ -209,10 +209,10 @@
reg = <2>;
label = "perf-l2-ret";
qcom,psci-mode = <3>;
- qcom,latency-us = <100>;
- qcom,ss-power = <640>;
- qcom,energy-overhead = <135000>;
- qcom,time-overhead = <85>;
+ qcom,latency-us = <368>;
+ qcom,ss-power = <277>;
+ qcom,energy-overhead = <240450>;
+ qcom,time-overhead = <700>;
qcom,min-child-idx = <2>;
};
@@ -220,10 +220,10 @@
reg = <3>;
label = "perf-l2-pc";
qcom,psci-mode = <0x4>;
- qcom,latency-us = <800>;
- qcom,ss-power = <450>;
- qcom,energy-overhead = <240000>;
- qcom,time-overhead = <11500>;
+ qcom,latency-us = <1609>;
+ qcom,ss-power = <262>;
+ qcom,energy-overhead = <703061>;
+ qcom,time-overhead = <2154>;
qcom,min-child-idx = <2>;
qcom,is-reset;
};
@@ -238,30 +238,30 @@
reg = <0>;
qcom,spm-cpu-mode = "wfi";
qcom,psci-cpu-mode = <0x1>;
- qcom,latency-us = <25>;
- qcom,ss-power = <750>;
- qcom,energy-overhead = <37000>;
- qcom,time-overhead = <50>;
+ qcom,latency-us = <39>;
+ qcom,ss-power = <315>;
+ qcom,energy-overhead = <37558>;
+ qcom,time-overhead = <83>;
};
qcom,pm-cpu-level@1 { /* C2D */
reg = <1>;
qcom,psci-cpu-mode = <2>;
qcom,spm-cpu-mode = "ret";
- qcom,latency-us = <40>;
- qcom,ss-power = <730>;
- qcom,energy-overhead = <85500>;
- qcom,time-overhead = <110>;
+ qcom,latency-us = <87>;
+ qcom,ss-power = <299>;
+ qcom,energy-overhead = <91434>;
+ qcom,time-overhead = <241>;
};
qcom,pm-cpu-level@2 { /* C3 */
reg = <2>;
qcom,spm-cpu-mode = "pc";
qcom,psci-cpu-mode = <0x3>;
- qcom,latency-us = <80>;
- qcom,ss-power = <700>;
- qcom,energy-overhead = <136480>;
- qcom,time-overhead = <160>;
+ qcom,latency-us = <301>;
+ qcom,ss-power = <291>;
+ qcom,energy-overhead = <199377>;
+ qcom,time-overhead = <563>;
qcom,is-reset;
};
};
diff --git a/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts b/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts
index c2408ba7bf76..deb10b591444 100644
--- a/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts
+++ b/arch/arm/boot/dts/qcom/sdm630-pm660a-qrd.dts
@@ -51,3 +51,35 @@
qcom,wsa-devs = <&wsa881x_211_en>, <&wsa881x_213_en>;
qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft";
};
+
+&pm660a_oledb {
+ status = "okay";
+ qcom,oledb-default-voltage-mv = <6400>;
+};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_rm67195_amoled_fhd_cmd>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+ oledb-supply = <&pm660a_oledb>;
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+ qcom,platform-reset-gpio = <&tlmm 53 0>;
+ qcom,platform-te-gpio = <&tlmm 59 0>;
+};
+
+&dsi_rm67195_amoled_fhd_cmd {
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <255>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply_labibb_amoled>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi
index cb083c0a8aa0..fb24f727fb49 100644
--- a/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-qrd.dtsi
@@ -197,6 +197,13 @@
status = "ok";
};
+&sdc2_cd_on {
+ config {
+ /delete-property/ bias-pull-up;
+ bias-disable;
+ };
+};
+
&sdhc_2 {
/* device core power supply */
vdd-supply = <&pm660l_l5>;
@@ -317,6 +324,12 @@
};
};
+&ssphy {
+ fpc-redrive-supply = <&pm660_l11>;
+ qcom,redrive-voltage-level = <0 1800000 1950000>;
+ qcom,redrive-load = <105000>;
+};
+
&soc {
qcom,msm-ssc-sensors {
compatible = "qcom,msm-ssc-sensors";
diff --git a/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi
index c16c83050f31..eded8b08528a 100644
--- a/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630-regulator.dtsi
@@ -376,6 +376,7 @@
pm660l_l7: regulator-l7 {
regulator-min-microvolt = <2700000>;
regulator-max-microvolt = <3125000>;
+ parent-supply = <&pm660_l10>;
status = "okay";
};
};
diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi
index 35a0709bd874..9626e0548789 100644
--- a/arch/arm/boot/dts/qcom/sdm630.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630.dtsi
@@ -34,7 +34,7 @@
chosen {
stdout-path = "serial0";
- bootargs = "rcupdate.rcu_expedited=1";
+ bootargs = "rcupdate.rcu_expedited=1 core_ctl_disable_cpumask=0-7";
};
psci {
diff --git a/arch/arm/boot/dts/qcom/sdm660-audio.dtsi b/arch/arm/boot/dts/qcom/sdm660-audio.dtsi
index c1cb6441cd43..402f19efd50d 100644
--- a/arch/arm/boot/dts/qcom/sdm660-audio.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-audio.dtsi
@@ -34,7 +34,7 @@
clock-names = "wcd_clk", "wcd_native_clk";
clocks = <&clock_audio AUDIO_PMI_CLK>,
- <&clock_audio AUDIO_AP_CLK2>;
+ <&clock_audio AUDIO_LPASS_MCLK>;
cdc-vdd-mic-bias-supply = <&pm660l_bob>;
qcom,cdc-vdd-mic-bias-voltage = <3300000 3300000>;
diff --git a/arch/arm/boot/dts/qcom/sdm660-bus.dtsi b/arch/arm/boot/dts/qcom/sdm660-bus.dtsi
index d555da4cbd08..6c956fc9b9d2 100644
--- a/arch/arm/boot/dts/qcom/sdm660-bus.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-bus.dtsi
@@ -324,9 +324,9 @@
qcom,qport = <4>;
qcom,qos-mode = "fixed";
qcom,connections = <&slv_hmss_l3 &slv_ebi>;
- qcom,prio-lvl = <0>;
- qcom,prio-rd = <0>;
- qcom,prio-wr = <0>;
+ qcom,prio-lvl = <1>;
+ qcom,prio-rd = <1>;
+ qcom,prio-wr = <1>;
qcom,bus-dev = <&fab_bimc>;
qcom,mas-rpm-id = <ICBID_MASTER_PIMEM>;
};
diff --git a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-cdp.dtsi
index e31a863ae22d..64ca4676ccd5 100644
--- a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-cdp.dtsi
@@ -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
@@ -229,7 +229,7 @@
reg = <0x0>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
- qcom,mount-angle = <270>;
+ qcom,mount-angle = <90>;
qcom,led-flash-src = <&led_flash0>;
qcom,actuator-src = <&actuator0>;
qcom,ois-src = <&ois0>;
diff --git a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi
index 416cd99a81cb..191beaa4d53b 100644
--- a/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-camera-sensor-mtp.dtsi
@@ -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
@@ -229,7 +229,7 @@
reg = <0x0>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
- qcom,mount-angle = <270>;
+ qcom,mount-angle = <90>;
qcom,led-flash-src = <&led_flash0>;
qcom,actuator-src = <&actuator0>;
qcom,ois-src = <&ois0>;
diff --git a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi
index 1f886f7f368f..f3b81b5df1de 100644
--- a/arch/arm/boot/dts/qcom/sdm660-camera.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-camera.dtsi
@@ -454,11 +454,11 @@
<&clock_mmss MMSS_CAMSS_CSI1_CLK>,
<&clock_mmss MMSS_CAMSS_CSI2_CLK>,
<&clock_mmss MMSS_CAMSS_CSI3_CLK>,
- <&clock_mmss MMSS_CAMSS_VFE0_CLK>,
<&clock_mmss VFE0_CLK_SRC>,
+ <&clock_mmss MMSS_CAMSS_VFE0_CLK>,
<&clock_mmss MMSS_CAMSS_CSI_VFE0_CLK>,
- <&clock_mmss MMSS_CAMSS_VFE1_CLK>,
<&clock_mmss VFE1_CLK_SRC>,
+ <&clock_mmss MMSS_CAMSS_VFE1_CLK>,
<&clock_mmss MMSS_CAMSS_CSI_VFE1_CLK>;
clock-names = "mmssnoc_axi", "mnoc_ahb_clk",
"camss_ahb_clk",
@@ -471,10 +471,12 @@
"csi2_pix_clk", "csi3_pix_clk",
"camss_csi0_clk", "camss_csi1_clk",
"camss_csi2_clk", "camss_csi3_clk",
+ "vfe0_clk_src",
"camss_vfe_vfe0_clk",
- "vfe0_clk_src", "camss_csi_vfe0_clk",
+ "camss_csi_vfe0_clk",
+ "vfe1_clk_src",
"camss_vfe_vfe1_clk",
- "vfe1_clk_src", "camss_csi_vfe1_clk";
+ "camss_csi_vfe1_clk";
qcom,clock-rates = <0 0 0 0 0
0 0 0 0
0 0 0 0
@@ -493,10 +495,10 @@
"NO_SET_RATE", "NO_SET_RATE",
"NO_SET_RATE", "NO_SET_RATE",
"NO_SET_RATE", "NO_SET_RATE",
- "NO_SET_RATE",
- "INIT_RATE", "NO_SET_RATE",
- "NO_SET_RATE",
- "INIT_RATE", "NO_SET_RATE";
+ "INIT_RATE",
+ "NO_SET_RATE", "NO_SET_RATE",
+ "INIT_RATE",
+ "NO_SET_RATE", "NO_SET_RATE";
status = "ok";
};
@@ -518,23 +520,23 @@
<&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>,
<&clock_mmss MMSS_CAMSS_AHB_CLK>,
<&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>,
+ <&clock_mmss VFE0_CLK_SRC>,
<&clock_mmss MMSS_CAMSS_VFE0_CLK>,
<&clock_mmss MMSS_CAMSS_VFE0_STREAM_CLK>,
<&clock_mmss MMSS_CAMSS_VFE0_AHB_CLK>,
<&clock_mmss MMSS_CAMSS_VFE_VBIF_AHB_CLK>,
<&clock_mmss MMSS_CAMSS_VFE_VBIF_AXI_CLK>,
- <&clock_mmss VFE0_CLK_SRC>,
<&clock_mmss MMSS_CAMSS_CSI_VFE0_CLK>;
clock-names = "mmssnoc_axi", "mnoc_ahb_clk",
"bimc_smmu_ahb_clk", "bimc_smmu_axi_clk",
- "camss_ahb_clk", "camss_top_ahb_clk",
+ "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src",
"camss_vfe_clk", "camss_vfe_stream_clk",
"camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk",
- "camss_vfe_vbif_axi_clk", "vfe_clk_src",
+ "camss_vfe_vbif_axi_clk",
"camss_csi_vfe_clk";
- qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 404000000 0
- 0 0 0 0 0 0 0 0 0 0 0 480000000 0
- 0 0 0 0 0 0 0 0 0 0 0 576000000 0>;
+ qcom,clock-rates = <0 0 0 0 0 0 404000000 0 0 0 0 0 0
+ 0 0 0 0 0 0 480000000 0 0 0 0 0 0
+ 0 0 0 0 0 0 576000000 0 0 0 0 0 0>;
status = "ok";
qos-entries = <8>;
qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418
@@ -599,23 +601,23 @@
<&clock_mmss MMSS_BIMC_SMMU_AXI_CLK>,
<&clock_mmss MMSS_CAMSS_AHB_CLK>,
<&clock_mmss MMSS_CAMSS_TOP_AHB_CLK>,
+ <&clock_mmss VFE1_CLK_SRC>,
<&clock_mmss MMSS_CAMSS_VFE1_CLK>,
<&clock_mmss MMSS_CAMSS_VFE1_STREAM_CLK>,
<&clock_mmss MMSS_CAMSS_VFE1_AHB_CLK>,
<&clock_mmss MMSS_CAMSS_VFE_VBIF_AHB_CLK>,
<&clock_mmss MMSS_CAMSS_VFE_VBIF_AXI_CLK>,
- <&clock_mmss VFE1_CLK_SRC>,
<&clock_mmss MMSS_CAMSS_CSI_VFE1_CLK>;
clock-names = "mmssnoc_axi", "mnoc_ahb_clk",
"bimc_smmu_ahb_clk", "bimc_smmu_axi_clk",
- "camss_ahb_clk", "camss_top_ahb_clk",
+ "camss_ahb_clk", "camss_top_ahb_clk", "vfe_clk_src",
"camss_vfe_clk", "camss_vfe_stream_clk",
"camss_vfe_ahb_clk", "camss_vfe_vbif_ahb_clk",
- "camss_vfe_vbif_axi_clk", "vfe_clk_src",
+ "camss_vfe_vbif_axi_clk",
"camss_csi_vfe_clk";
- qcom,clock-rates = <0 0 0 0 0 0 0 0 0 0 0 404000000 0
- 0 0 0 0 0 0 0 0 0 0 0 480000000 0
- 0 0 0 0 0 0 0 0 0 0 0 576000000 0>;
+ qcom,clock-rates = <0 0 0 0 0 0 404000000 0 0 0 0 0 0
+ 0 0 0 0 0 0 480000000 0 0 0 0 0 0
+ 0 0 0 0 0 0 576000000 0 0 0 0 0 0>;
status = "ok";
qos-entries = <8>;
qos-regs = <0x404 0x408 0x40c 0x410 0x414 0x418
diff --git a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi
index c3c776be3209..f5d61d440a27 100644
--- a/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-gpu.dtsi
@@ -141,9 +141,6 @@
qcom,gpu-speed-bin = <0x41a0 0x1fe00000 21>;
- /* Enable midframe sampling */
- qcom,enable-midframe-timer;
-
/* GPU Mempools */
qcom,gpu-mempools {
#address-cells= <1>;
diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi
index 4794e648752b..b263d2a68792 100644
--- a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi
@@ -593,6 +593,19 @@
qcom,mdss-default-ot-rd-limit = <32>;
qcom,mdss-default-ot-wr-limit = <32>;
+
+ qcom,sde-reg-bus {
+ /* Reg Bus Scale Settings */
+ qcom,msm-bus,name = "mdss_rot_reg";
+ qcom,msm-bus,num-cases = <4>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,vectors-KBps =
+ <1 590 0 0>,
+ <1 590 0 76800>,
+ <1 590 0 160000>,
+ <1 590 0 320000>;
+ };
};
};
diff --git a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi
index 0e869f0e1352..3d2cfedc1009 100644
--- a/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-qrd.dtsi
@@ -196,6 +196,12 @@
};
};
+&ssphy {
+ fpc-redrive-supply = <&pm660_l11>;
+ qcom,redrive-voltage-level = <0 1800000 1950000>;
+ qcom,redrive-load = <105000>;
+};
+
&soc {
gpio_keys {
compatible = "gpio-keys";
diff --git a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
index 462a76ef8bfe..a93efdc38f41 100644
--- a/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660-regulator.dtsi
@@ -377,6 +377,7 @@
pm660l_l7: regulator-l7 {
regulator-min-microvolt = <2700000>;
regulator-max-microvolt = <3125000>;
+ parent-supply = <&pm660_l10>;
status = "okay";
};
};
diff --git a/arch/arm/configs/sdm660-perf_defconfig b/arch/arm/configs/sdm660-perf_defconfig
index 21650ead5a34..32cf48661c9b 100644
--- a/arch/arm/configs/sdm660-perf_defconfig
+++ b/arch/arm/configs/sdm660-perf_defconfig
@@ -472,7 +472,6 @@ CONFIG_USB_CONFIGFS_UEVENT=y
CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_DIAG=y
-CONFIG_USB_CONFIGFS_F_GSI=y
CONFIG_USB_CONFIGFS_F_CDEV=y
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
diff --git a/arch/arm/configs/sdm660_defconfig b/arch/arm/configs/sdm660_defconfig
index 02b15745e882..c4b0eabe2fbf 100644
--- a/arch/arm/configs/sdm660_defconfig
+++ b/arch/arm/configs/sdm660_defconfig
@@ -471,7 +471,6 @@ CONFIG_USB_CONFIGFS_UEVENT=y
CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_DIAG=y
-CONFIG_USB_CONFIGFS_F_GSI=y
CONFIG_USB_CONFIGFS_F_CDEV=y
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index c7ba9a42e857..ebf866a3a8c8 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -205,18 +205,12 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
* and iterate over the range.
*/
- bool need_flush = !vcpu_has_cache_enabled(vcpu) || ipa_uncached;
-
VM_BUG_ON(size & ~PAGE_MASK);
- if (!need_flush && !icache_is_pipt())
- goto vipt_cache;
-
while (size) {
void *va = kmap_atomic_pfn(pfn);
- if (need_flush)
- kvm_flush_dcache_to_poc(va, PAGE_SIZE);
+ kvm_flush_dcache_to_poc(va, PAGE_SIZE);
if (icache_is_pipt())
__cpuc_coherent_user_range((unsigned long)va,
@@ -228,7 +222,6 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
kunmap_atomic(va);
}
-vipt_cache:
if (!icache_is_pipt() && !icache_is_vivt_asid_tagged()) {
/* any kind of VIPT cache */
__flush_icache_all();
diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S
index 8ecfd15c3a02..df73914e81c8 100644
--- a/arch/arm/lib/getuser.S
+++ b/arch/arm/lib/getuser.S
@@ -67,7 +67,7 @@ ENTRY(__get_user_4)
ENDPROC(__get_user_4)
ENTRY(__get_user_8)
- check_uaccess r0, 8, r1, r2, __get_user_bad
+ check_uaccess r0, 8, r1, r2, __get_user_bad8
#ifdef CONFIG_THUMB2_KERNEL
5: TUSER(ldr) r2, [r0]
6: TUSER(ldr) r3, [r0, #4]
diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig
index b15e01bfa51b..0031c55360c7 100644
--- a/arch/arm64/configs/msm-perf_defconfig
+++ b/arch/arm64/configs/msm-perf_defconfig
@@ -438,7 +438,6 @@ CONFIG_USB_CONFIGFS_SERIAL=y
CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_ECM=y
CONFIG_USB_CONFIGFS_QCRNDIS=y
-CONFIG_USB_CONFIGFS_RNDIS=y
CONFIG_USB_CONFIGFS_RMNET_BAM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig
index 988f1fbf8ea3..261a49d7944a 100644
--- a/arch/arm64/configs/msm_defconfig
+++ b/arch/arm64/configs/msm_defconfig
@@ -423,7 +423,6 @@ CONFIG_USB_CONFIGFS_SERIAL=y
CONFIG_USB_CONFIGFS_NCM=y
CONFIG_USB_CONFIGFS_ECM=y
CONFIG_USB_CONFIGFS_QCRNDIS=y
-CONFIG_USB_CONFIGFS_RNDIS=y
CONFIG_USB_CONFIGFS_RMNET_BAM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
diff --git a/arch/arm64/configs/msmcortex_mediabox_defconfig b/arch/arm64/configs/msmcortex_mediabox_defconfig
index ccf3653ee817..ccd653eaec7d 100644
--- a/arch/arm64/configs/msmcortex_mediabox_defconfig
+++ b/arch/arm64/configs/msmcortex_mediabox_defconfig
@@ -282,6 +282,7 @@ CONFIG_WIL6210=m
CONFIG_ATH10K=m
CONFIG_ATH10K_TARGET_SNOC=m
CONFIG_ATH10K_SNOC=y
+CONFIG_ATH10K_DEBUG=y
CONFIG_CLD_LL_CORE=y
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_KEYRESET=y
diff --git a/arch/arm64/configs/sdm660-perf_defconfig b/arch/arm64/configs/sdm660-perf_defconfig
index 7084d2098e8c..ffb983587c31 100644
--- a/arch/arm64/configs/sdm660-perf_defconfig
+++ b/arch/arm64/configs/sdm660-perf_defconfig
@@ -471,7 +471,6 @@ CONFIG_USB_CONFIGFS_UEVENT=y
CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_DIAG=y
-CONFIG_USB_CONFIGFS_F_GSI=y
CONFIG_USB_CONFIGFS_F_CDEV=y
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
diff --git a/arch/arm64/configs/sdm660_defconfig b/arch/arm64/configs/sdm660_defconfig
index 69ea4418e8d9..bba52749284a 100644
--- a/arch/arm64/configs/sdm660_defconfig
+++ b/arch/arm64/configs/sdm660_defconfig
@@ -474,7 +474,6 @@ CONFIG_USB_CONFIGFS_UEVENT=y
CONFIG_USB_CONFIGFS_F_MIDI=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_DIAG=y
-CONFIG_USB_CONFIGFS_F_GSI=y
CONFIG_USB_CONFIGFS_F_CDEV=y
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
@@ -502,6 +501,7 @@ CONFIG_EDAC=y
CONFIG_EDAC_MM_EDAC=y
CONFIG_EDAC_CORTEX_ARM64=y
CONFIG_EDAC_CORTEX_ARM64_PANIC_ON_CE=y
+CONFIG_EDAC_CORTEX_ARM64_DBE_IRQ_ONLY=y
CONFIG_EDAC_CORTEX_ARM64_PANIC_ON_UE=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_QPNP=y
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 342a5ac2f3da..320dc9c7e4f4 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -237,8 +237,7 @@ static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
{
void *va = page_address(pfn_to_page(pfn));
- if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached)
- kvm_flush_dcache_to_poc(va, size);
+ kvm_flush_dcache_to_poc(va, size);
if (!icache_is_aliasing()) { /* PIPT */
flush_icache_range((unsigned long)va,
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 8cfd5ab37743..a1c2ac38771d 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -664,7 +664,7 @@ ENDPROC(__secondary_switched)
*/
.section ".idmap.text", "ax"
ENTRY(__enable_mmu)
- mrs x18, sctlr_el1 // preserve old SCTLR_EL1 value
+ mrs x22, sctlr_el1 // preserve old SCTLR_EL1 value
mrs x1, ID_AA64MMFR0_EL1
ubfx x2, x1, #ID_AA64MMFR0_TGRAN_SHIFT, 4
cmp x2, #ID_AA64MMFR0_TGRAN_SUPPORTED
@@ -691,7 +691,7 @@ ENTRY(__enable_mmu)
* to take into account by discarding the current kernel mapping and
* creating a new one.
*/
- msr sctlr_el1, x18 // disable the MMU
+ msr sctlr_el1, x22 // disable the MMU
isb
bl __create_page_tables // recreate kernel mapping
diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c
index b05469173ba5..310f2f463cd4 100644
--- a/arch/arm64/kernel/kaslr.c
+++ b/arch/arm64/kernel/kaslr.c
@@ -130,11 +130,15 @@ u64 __init kaslr_early_init(u64 dt_phys, u64 modulo_offset)
/*
* The kernel Image should not extend across a 1GB/32MB/512MB alignment
* boundary (for 4KB/16KB/64KB granule kernels, respectively). If this
- * happens, increase the KASLR offset by the size of the kernel image.
+ * happens, increase the KASLR offset by the size of the kernel image
+ * rounded up by SWAPPER_BLOCK_SIZE.
*/
if ((((u64)_text + offset + modulo_offset) >> SWAPPER_TABLE_SHIFT) !=
- (((u64)_end + offset + modulo_offset) >> SWAPPER_TABLE_SHIFT))
- offset = (offset + (u64)(_end - _text)) & mask;
+ (((u64)_end + offset + modulo_offset) >> SWAPPER_TABLE_SHIFT)) {
+ u64 kimg_sz = _end - _text;
+ offset = (offset + round_up(kimg_sz, SWAPPER_BLOCK_SIZE))
+ & mask;
+ }
if (IS_ENABLED(CONFIG_KASAN))
/*
diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c
index 52caa75bfe4e..e2f50d690624 100644
--- a/arch/mips/bcm47xx/buttons.c
+++ b/arch/mips/bcm47xx/buttons.c
@@ -17,6 +17,12 @@
.active_low = 1, \
}
+#define BCM47XX_GPIO_KEY_H(_gpio, _code) \
+ { \
+ .code = _code, \
+ .gpio = _gpio, \
+ }
+
/* Asus */
static const struct gpio_keys_button
@@ -79,8 +85,8 @@ bcm47xx_buttons_asus_wl500gpv2[] __initconst = {
static const struct gpio_keys_button
bcm47xx_buttons_asus_wl500w[] __initconst = {
- BCM47XX_GPIO_KEY(6, KEY_RESTART),
- BCM47XX_GPIO_KEY(7, KEY_WPS_BUTTON),
+ BCM47XX_GPIO_KEY_H(6, KEY_RESTART),
+ BCM47XX_GPIO_KEY_H(7, KEY_WPS_BUTTON),
};
static const struct gpio_keys_button
diff --git a/arch/mips/cavium-octeon/octeon-memcpy.S b/arch/mips/cavium-octeon/octeon-memcpy.S
index 64e08df51d65..8b7004132491 100644
--- a/arch/mips/cavium-octeon/octeon-memcpy.S
+++ b/arch/mips/cavium-octeon/octeon-memcpy.S
@@ -208,18 +208,18 @@ EXC( STORE t2, UNIT(6)(dst), s_exc_p10u)
ADD src, src, 16*NBYTES
EXC( STORE t3, UNIT(7)(dst), s_exc_p9u)
ADD dst, dst, 16*NBYTES
-EXC( LOAD t0, UNIT(-8)(src), l_exc_copy)
-EXC( LOAD t1, UNIT(-7)(src), l_exc_copy)
-EXC( LOAD t2, UNIT(-6)(src), l_exc_copy)
-EXC( LOAD t3, UNIT(-5)(src), l_exc_copy)
+EXC( LOAD t0, UNIT(-8)(src), l_exc_copy_rewind16)
+EXC( LOAD t1, UNIT(-7)(src), l_exc_copy_rewind16)
+EXC( LOAD t2, UNIT(-6)(src), l_exc_copy_rewind16)
+EXC( LOAD t3, UNIT(-5)(src), l_exc_copy_rewind16)
EXC( STORE t0, UNIT(-8)(dst), s_exc_p8u)
EXC( STORE t1, UNIT(-7)(dst), s_exc_p7u)
EXC( STORE t2, UNIT(-6)(dst), s_exc_p6u)
EXC( STORE t3, UNIT(-5)(dst), s_exc_p5u)
-EXC( LOAD t0, UNIT(-4)(src), l_exc_copy)
-EXC( LOAD t1, UNIT(-3)(src), l_exc_copy)
-EXC( LOAD t2, UNIT(-2)(src), l_exc_copy)
-EXC( LOAD t3, UNIT(-1)(src), l_exc_copy)
+EXC( LOAD t0, UNIT(-4)(src), l_exc_copy_rewind16)
+EXC( LOAD t1, UNIT(-3)(src), l_exc_copy_rewind16)
+EXC( LOAD t2, UNIT(-2)(src), l_exc_copy_rewind16)
+EXC( LOAD t3, UNIT(-1)(src), l_exc_copy_rewind16)
EXC( STORE t0, UNIT(-4)(dst), s_exc_p4u)
EXC( STORE t1, UNIT(-3)(dst), s_exc_p3u)
EXC( STORE t2, UNIT(-2)(dst), s_exc_p2u)
@@ -383,6 +383,10 @@ done:
nop
END(memcpy)
+l_exc_copy_rewind16:
+ /* Rewind src and dst by 16*NBYTES for l_exc_copy */
+ SUB src, src, 16*NBYTES
+ SUB dst, dst, 16*NBYTES
l_exc_copy:
/*
* Copy bytes from src until faulting load address (or until a
diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig
index 57ed466e00db..2f140d75d01c 100644
--- a/arch/mips/configs/ip22_defconfig
+++ b/arch/mips/configs/ip22_defconfig
@@ -68,8 +68,8 @@ CONFIG_NETFILTER_NETLINK_QUEUE=m
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig
index 48e16d98b2cc..b15508447366 100644
--- a/arch/mips/configs/ip27_defconfig
+++ b/arch/mips/configs/ip27_defconfig
@@ -134,7 +134,7 @@ CONFIG_LIBFC=m
CONFIG_SCSI_QLOGIC_1280=y
CONFIG_SCSI_PMCRAID=m
CONFIG_SCSI_BFA_FC=m
-CONFIG_SCSI_DH=m
+CONFIG_SCSI_DH=y
CONFIG_SCSI_DH_RDAC=m
CONFIG_SCSI_DH_HP_SW=m
CONFIG_SCSI_DH_EMC=m
@@ -206,7 +206,6 @@ CONFIG_MLX4_EN=m
# CONFIG_MLX4_DEBUG is not set
CONFIG_TEHUTI=m
CONFIG_BNX2X=m
-CONFIG_QLGE=m
CONFIG_SFC=m
CONFIG_BE2NET=m
CONFIG_LIBERTAS_THINFIRM=m
diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig
index 004cf52d1b7d..c24b87819ccb 100644
--- a/arch/mips/configs/lemote2f_defconfig
+++ b/arch/mips/configs/lemote2f_defconfig
@@ -39,7 +39,7 @@ CONFIG_HIBERNATION=y
CONFIG_PM_STD_PARTITION="/dev/hda3"
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_DEBUG=y
-CONFIG_CPU_FREQ_STAT=m
+CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_FREQ_STAT_DETAILS=y
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=m
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig
index 5afb4840aec7..739ccd0dca64 100644
--- a/arch/mips/configs/malta_defconfig
+++ b/arch/mips/configs/malta_defconfig
@@ -59,8 +59,8 @@ CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
diff --git a/arch/mips/configs/malta_kvm_defconfig b/arch/mips/configs/malta_kvm_defconfig
index 98f13879bb8f..47f4ecf125ba 100644
--- a/arch/mips/configs/malta_kvm_defconfig
+++ b/arch/mips/configs/malta_kvm_defconfig
@@ -60,8 +60,8 @@ CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
diff --git a/arch/mips/configs/malta_kvm_guest_defconfig b/arch/mips/configs/malta_kvm_guest_defconfig
index 3b5d5913f548..e79d325aa085 100644
--- a/arch/mips/configs/malta_kvm_guest_defconfig
+++ b/arch/mips/configs/malta_kvm_guest_defconfig
@@ -59,8 +59,8 @@ CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
diff --git a/arch/mips/configs/maltaup_xpa_defconfig b/arch/mips/configs/maltaup_xpa_defconfig
index 732215732751..ae87ad86243b 100644
--- a/arch/mips/configs/maltaup_xpa_defconfig
+++ b/arch/mips/configs/maltaup_xpa_defconfig
@@ -61,8 +61,8 @@ CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
diff --git a/arch/mips/configs/nlm_xlp_defconfig b/arch/mips/configs/nlm_xlp_defconfig
index b3d1d37f85ea..47492fee2952 100644
--- a/arch/mips/configs/nlm_xlp_defconfig
+++ b/arch/mips/configs/nlm_xlp_defconfig
@@ -111,7 +111,7 @@ CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_UDPLITE=y
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig
index 3d8016d6cf3e..472a818f1eb8 100644
--- a/arch/mips/configs/nlm_xlr_defconfig
+++ b/arch/mips/configs/nlm_xlr_defconfig
@@ -91,7 +91,7 @@ CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_SECMARK=y
CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_UDPLITE=y
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S
index 8c6f508e59de..554d1da97743 100644
--- a/arch/mips/dec/int-handler.S
+++ b/arch/mips/dec/int-handler.S
@@ -146,7 +146,25 @@
/*
* Find irq with highest priority
*/
- PTR_LA t1,cpu_mask_nr_tbl
+ # open coded PTR_LA t1, cpu_mask_nr_tbl
+#if (_MIPS_SZPTR == 32)
+ # open coded la t1, cpu_mask_nr_tbl
+ lui t1, %hi(cpu_mask_nr_tbl)
+ addiu t1, %lo(cpu_mask_nr_tbl)
+
+#endif
+#if (_MIPS_SZPTR == 64)
+ # open coded dla t1, cpu_mask_nr_tbl
+ .set push
+ .set noat
+ lui t1, %highest(cpu_mask_nr_tbl)
+ lui AT, %hi(cpu_mask_nr_tbl)
+ daddiu t1, t1, %higher(cpu_mask_nr_tbl)
+ daddiu AT, AT, %lo(cpu_mask_nr_tbl)
+ dsll t1, 32
+ daddu t1, t1, AT
+ .set pop
+#endif
1: lw t2,(t1)
nop
and t2,t0
@@ -195,7 +213,25 @@
/*
* Find irq with highest priority
*/
- PTR_LA t1,asic_mask_nr_tbl
+ # open coded PTR_LA t1,asic_mask_nr_tbl
+#if (_MIPS_SZPTR == 32)
+ # open coded la t1, asic_mask_nr_tbl
+ lui t1, %hi(asic_mask_nr_tbl)
+ addiu t1, %lo(asic_mask_nr_tbl)
+
+#endif
+#if (_MIPS_SZPTR == 64)
+ # open coded dla t1, asic_mask_nr_tbl
+ .set push
+ .set noat
+ lui t1, %highest(asic_mask_nr_tbl)
+ lui AT, %hi(asic_mask_nr_tbl)
+ daddiu t1, t1, %higher(asic_mask_nr_tbl)
+ daddiu AT, AT, %lo(asic_mask_nr_tbl)
+ dsll t1, 32
+ daddu t1, t1, AT
+ .set pop
+#endif
2: lw t2,(t1)
nop
and t2,t0
diff --git a/arch/mips/include/asm/checksum.h b/arch/mips/include/asm/checksum.h
index 3ceacde5eb6e..17f89f9670b2 100644
--- a/arch/mips/include/asm/checksum.h
+++ b/arch/mips/include/asm/checksum.h
@@ -186,7 +186,9 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr,
" daddu %0, %4 \n"
" dsll32 $1, %0, 0 \n"
" daddu %0, $1 \n"
+ " sltu $1, %0, $1 \n"
" dsra32 %0, %0, 0 \n"
+ " addu %0, $1 \n"
#endif
" .set pop"
: "=r" (sum)
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 44a6f25e902e..fc537d1b649d 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -191,11 +191,9 @@ struct mips_frame_info {
#define J_TARGET(pc,target) \
(((unsigned long)(pc) & 0xf0000000) | ((target) << 2))
-static inline int is_ra_save_ins(union mips_instruction *ip)
+static inline int is_ra_save_ins(union mips_instruction *ip, int *poff)
{
#ifdef CONFIG_CPU_MICROMIPS
- union mips_instruction mmi;
-
/*
* swsp ra,offset
* swm16 reglist,offset(sp)
@@ -205,29 +203,71 @@ static inline int is_ra_save_ins(union mips_instruction *ip)
*
* microMIPS is way more fun...
*/
- if (mm_insn_16bit(ip->halfword[0])) {
- mmi.word = (ip->halfword[0] << 16);
- return (mmi.mm16_r5_format.opcode == mm_swsp16_op &&
- mmi.mm16_r5_format.rt == 31) ||
- (mmi.mm16_m_format.opcode == mm_pool16c_op &&
- mmi.mm16_m_format.func == mm_swm16_op);
+ if (mm_insn_16bit(ip->halfword[1])) {
+ switch (ip->mm16_r5_format.opcode) {
+ case mm_swsp16_op:
+ if (ip->mm16_r5_format.rt != 31)
+ return 0;
+
+ *poff = ip->mm16_r5_format.simmediate;
+ *poff = (*poff << 2) / sizeof(ulong);
+ return 1;
+
+ case mm_pool16c_op:
+ switch (ip->mm16_m_format.func) {
+ case mm_swm16_op:
+ *poff = ip->mm16_m_format.imm;
+ *poff += 1 + ip->mm16_m_format.rlist;
+ *poff = (*poff << 2) / sizeof(ulong);
+ return 1;
+
+ default:
+ return 0;
+ }
+
+ default:
+ return 0;
+ }
}
- else {
- mmi.halfword[0] = ip->halfword[1];
- mmi.halfword[1] = ip->halfword[0];
- return (mmi.mm_m_format.opcode == mm_pool32b_op &&
- mmi.mm_m_format.rd > 9 &&
- mmi.mm_m_format.base == 29 &&
- mmi.mm_m_format.func == mm_swm32_func) ||
- (mmi.i_format.opcode == mm_sw32_op &&
- mmi.i_format.rs == 29 &&
- mmi.i_format.rt == 31);
+
+ switch (ip->i_format.opcode) {
+ case mm_sw32_op:
+ if (ip->i_format.rs != 29)
+ return 0;
+ if (ip->i_format.rt != 31)
+ return 0;
+
+ *poff = ip->i_format.simmediate / sizeof(ulong);
+ return 1;
+
+ case mm_pool32b_op:
+ switch (ip->mm_m_format.func) {
+ case mm_swm32_func:
+ if (ip->mm_m_format.rd < 0x10)
+ return 0;
+ if (ip->mm_m_format.base != 29)
+ return 0;
+
+ *poff = ip->mm_m_format.simmediate;
+ *poff += (ip->mm_m_format.rd & 0xf) * sizeof(u32);
+ *poff /= sizeof(ulong);
+ return 1;
+ default:
+ return 0;
+ }
+
+ default:
+ return 0;
}
#else
/* sw / sd $ra, offset($sp) */
- return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
- ip->i_format.rs == 29 &&
- ip->i_format.rt == 31;
+ if ((ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
+ ip->i_format.rs == 29 && ip->i_format.rt == 31) {
+ *poff = ip->i_format.simmediate / sizeof(ulong);
+ return 1;
+ }
+
+ return 0;
#endif
}
@@ -242,13 +282,16 @@ static inline int is_jump_ins(union mips_instruction *ip)
*
* microMIPS is kind of more fun...
*/
- union mips_instruction mmi;
-
- mmi.word = (ip->halfword[0] << 16);
+ if (mm_insn_16bit(ip->halfword[1])) {
+ if ((ip->mm16_r5_format.opcode == mm_pool16c_op &&
+ (ip->mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op))
+ return 1;
+ return 0;
+ }
- if ((mmi.mm16_r5_format.opcode == mm_pool16c_op &&
- (mmi.mm16_r5_format.rt & mm_jr16_op) == mm_jr16_op) ||
- ip->j_format.opcode == mm_jal32_op)
+ if (ip->j_format.opcode == mm_j32_op)
+ return 1;
+ if (ip->j_format.opcode == mm_jal32_op)
return 1;
if (ip->r_format.opcode != mm_pool32a_op ||
ip->r_format.func != mm_pool32axf_op)
@@ -276,15 +319,13 @@ static inline int is_sp_move_ins(union mips_instruction *ip)
*
* microMIPS is not more fun...
*/
- if (mm_insn_16bit(ip->halfword[0])) {
- union mips_instruction mmi;
-
- mmi.word = (ip->halfword[0] << 16);
- return (mmi.mm16_r3_format.opcode == mm_pool16d_op &&
- mmi.mm16_r3_format.simmediate && mm_addiusp_func) ||
- (mmi.mm16_r5_format.opcode == mm_pool16d_op &&
- mmi.mm16_r5_format.rt == 29);
+ if (mm_insn_16bit(ip->halfword[1])) {
+ return (ip->mm16_r3_format.opcode == mm_pool16d_op &&
+ ip->mm16_r3_format.simmediate && mm_addiusp_func) ||
+ (ip->mm16_r5_format.opcode == mm_pool16d_op &&
+ ip->mm16_r5_format.rt == 29);
}
+
return ip->mm_i_format.opcode == mm_addiu32_op &&
ip->mm_i_format.rt == 29 && ip->mm_i_format.rs == 29;
#else
@@ -299,30 +340,36 @@ static inline int is_sp_move_ins(union mips_instruction *ip)
static int get_frame_info(struct mips_frame_info *info)
{
-#ifdef CONFIG_CPU_MICROMIPS
- union mips_instruction *ip = (void *) (((char *) info->func) - 1);
-#else
- union mips_instruction *ip = info->func;
-#endif
- unsigned max_insns = info->func_size / sizeof(union mips_instruction);
- unsigned i;
+ bool is_mmips = IS_ENABLED(CONFIG_CPU_MICROMIPS);
+ union mips_instruction insn, *ip, *ip_end;
+ const unsigned int max_insns = 128;
+ unsigned int i;
info->pc_offset = -1;
info->frame_size = 0;
+ ip = (void *)msk_isa16_mode((ulong)info->func);
if (!ip)
goto err;
- if (max_insns == 0)
- max_insns = 128U; /* unknown function size */
- max_insns = min(128U, max_insns);
+ ip_end = (void *)ip + info->func_size;
- for (i = 0; i < max_insns; i++, ip++) {
+ for (i = 0; i < max_insns && ip < ip_end; i++, ip++) {
+ if (is_mmips && mm_insn_16bit(ip->halfword[0])) {
+ insn.halfword[0] = 0;
+ insn.halfword[1] = ip->halfword[0];
+ } else if (is_mmips) {
+ insn.halfword[0] = ip->halfword[1];
+ insn.halfword[1] = ip->halfword[0];
+ } else {
+ insn.word = ip->word;
+ }
- if (is_jump_ins(ip))
+ if (is_jump_ins(&insn))
break;
+
if (!info->frame_size) {
- if (is_sp_move_ins(ip))
+ if (is_sp_move_ins(&insn))
{
#ifdef CONFIG_CPU_MICROMIPS
if (mm_insn_16bit(ip->halfword[0]))
@@ -345,11 +392,9 @@ static int get_frame_info(struct mips_frame_info *info)
}
continue;
}
- if (info->pc_offset == -1 && is_ra_save_ins(ip)) {
- info->pc_offset =
- ip->i_format.simmediate / sizeof(long);
+ if (info->pc_offset == -1 &&
+ is_ra_save_ins(&insn, &info->pc_offset))
break;
- }
}
if (info->frame_size && info->pc_offset >= 0) /* nested */
return 0;
diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
index 80554e8f6037..3e390a4e3897 100644
--- a/arch/mips/lantiq/xway/sysctrl.c
+++ b/arch/mips/lantiq/xway/sysctrl.c
@@ -545,7 +545,7 @@ void __init ltq_soc_init(void)
clkdev_add_pmu("1a800000.pcie", "msi", 1, 1, PMU1_PCIE2_MSI);
clkdev_add_pmu("1a800000.pcie", "pdi", 1, 1, PMU1_PCIE2_PDI);
clkdev_add_pmu("1a800000.pcie", "ctl", 1, 1, PMU1_PCIE2_CTL);
- clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH | PMU_PPE_DP);
+ clkdev_add_pmu("1e108000.eth", NULL, 0, 0, PMU_SWITCH | PMU_PPE_DP);
clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
} else if (of_machine_is_compatible("lantiq,ar10")) {
@@ -553,7 +553,7 @@ void __init ltq_soc_init(void)
ltq_ar10_fpi_hz(), ltq_ar10_pp32_hz());
clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
clkdev_add_pmu("1e106000.usb", "ctl", 1, 0, PMU_USB1);
- clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH |
+ clkdev_add_pmu("1e108000.eth", NULL, 0, 0, PMU_SWITCH |
PMU_PPE_DP | PMU_PPE_TC);
clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY);
@@ -575,11 +575,11 @@ void __init ltq_soc_init(void)
clkdev_add_pmu(NULL, "ahb", 1, 0, PMU_AHBM | PMU_AHBS);
clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
- clkdev_add_pmu("1e108000.eth", NULL, 1, 0,
+ clkdev_add_pmu("1e108000.eth", NULL, 0, 0,
PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM |
PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
PMU_PPE_QSB | PMU_PPE_TOP);
- clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY);
+ clkdev_add_pmu("1f203000.rcu", "gphy", 0, 0, PMU_GPHY);
clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO);
clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
diff --git a/arch/mips/mm/sc-ip22.c b/arch/mips/mm/sc-ip22.c
index dc7c5a5214a9..efaf364fe581 100644
--- a/arch/mips/mm/sc-ip22.c
+++ b/arch/mips/mm/sc-ip22.c
@@ -31,26 +31,40 @@ static inline void indy_sc_wipe(unsigned long first, unsigned long last)
unsigned long tmp;
__asm__ __volatile__(
- ".set\tpush\t\t\t# indy_sc_wipe\n\t"
- ".set\tnoreorder\n\t"
- ".set\tmips3\n\t"
- ".set\tnoat\n\t"
- "mfc0\t%2, $12\n\t"
- "li\t$1, 0x80\t\t\t# Go 64 bit\n\t"
- "mtc0\t$1, $12\n\t"
-
- "dli\t$1, 0x9000000080000000\n\t"
- "or\t%0, $1\t\t\t# first line to flush\n\t"
- "or\t%1, $1\t\t\t# last line to flush\n\t"
- ".set\tat\n\t"
-
- "1:\tsw\t$0, 0(%0)\n\t"
- "bne\t%0, %1, 1b\n\t"
- " daddu\t%0, 32\n\t"
-
- "mtc0\t%2, $12\t\t\t# Back to 32 bit\n\t"
- "nop; nop; nop; nop;\n\t"
- ".set\tpop"
+ " .set push # indy_sc_wipe \n"
+ " .set noreorder \n"
+ " .set mips3 \n"
+ " .set noat \n"
+ " mfc0 %2, $12 \n"
+ " li $1, 0x80 # Go 64 bit \n"
+ " mtc0 $1, $12 \n"
+ " \n"
+ " # \n"
+ " # Open code a dli $1, 0x9000000080000000 \n"
+ " # \n"
+ " # Required because binutils 2.25 will happily accept \n"
+ " # 64 bit instructions in .set mips3 mode but puke on \n"
+ " # 64 bit constants when generating 32 bit ELF \n"
+ " # \n"
+ " lui $1,0x9000 \n"
+ " dsll $1,$1,0x10 \n"
+ " ori $1,$1,0x8000 \n"
+ " dsll $1,$1,0x10 \n"
+ " \n"
+ " or %0, $1 # first line to flush \n"
+ " or %1, $1 # last line to flush \n"
+ " .set at \n"
+ " \n"
+ "1: sw $0, 0(%0) \n"
+ " bne %0, %1, 1b \n"
+ " daddu %0, 32 \n"
+ " \n"
+ " mtc0 %2, $12 # Back to 32 bit \n"
+ " nop # pipeline hazard \n"
+ " nop \n"
+ " nop \n"
+ " nop \n"
+ " .set pop \n"
: "=r" (first), "=r" (last), "=&r" (tmp)
: "0" (first), "1" (last));
}
diff --git a/arch/mips/netlogic/common/reset.S b/arch/mips/netlogic/common/reset.S
index edbab9b8691f..c474981a6c0d 100644
--- a/arch/mips/netlogic/common/reset.S
+++ b/arch/mips/netlogic/common/reset.S
@@ -50,7 +50,6 @@
#include <asm/netlogic/xlp-hal/sys.h>
#include <asm/netlogic/xlp-hal/cpucontrol.h>
-#define CP0_EBASE $15
#define SYS_CPU_COHERENT_BASE CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \
XLP_IO_SYS_OFFSET(0) + XLP_IO_PCI_HDRSZ + \
SYS_CPU_NONCOHERENT_MODE * 4
@@ -92,7 +91,7 @@
* registers. On XLPII CPUs, usual cache instructions work.
*/
.macro xlp_flush_l1_dcache
- mfc0 t0, CP0_EBASE, 0
+ mfc0 t0, CP0_PRID
andi t0, t0, PRID_IMP_MASK
slt t1, t0, 0x1200
beqz t1, 15f
@@ -171,7 +170,7 @@ FEXPORT(nlm_reset_entry)
nop
1: /* Entry point on core wakeup */
- mfc0 t0, CP0_EBASE, 0 /* processor ID */
+ mfc0 t0, CP0_PRID /* processor ID */
andi t0, PRID_IMP_MASK
li t1, 0x1500 /* XLP 9xx */
beq t0, t1, 2f /* does not need to set coherent */
@@ -182,8 +181,8 @@ FEXPORT(nlm_reset_entry)
nop
/* set bit in SYS coherent register for the core */
- mfc0 t0, CP0_EBASE, 1
- mfc0 t1, CP0_EBASE, 1
+ mfc0 t0, CP0_EBASE
+ mfc0 t1, CP0_EBASE
srl t1, 5
andi t1, 0x3 /* t1 <- node */
li t2, 0x40000
@@ -232,7 +231,7 @@ EXPORT(nlm_boot_siblings)
* NOTE: All GPR contents are lost after the mtcr above!
*/
- mfc0 v0, CP0_EBASE, 1
+ mfc0 v0, CP0_EBASE
andi v0, 0x3ff /* v0 <- node/core */
/*
diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S
index 805355b0bd05..f0cc4c9de2bb 100644
--- a/arch/mips/netlogic/common/smpboot.S
+++ b/arch/mips/netlogic/common/smpboot.S
@@ -48,8 +48,6 @@
#include <asm/netlogic/xlp-hal/sys.h>
#include <asm/netlogic/xlp-hal/cpucontrol.h>
-#define CP0_EBASE $15
-
.set noreorder
.set noat
.set arch=xlr /* for mfcr/mtcr, XLR is sufficient */
@@ -86,7 +84,7 @@ NESTED(nlm_boot_secondary_cpus, 16, sp)
PTR_L gp, 0(t1)
/* a0 has the processor id */
- mfc0 a0, CP0_EBASE, 1
+ mfc0 a0, CP0_EBASE
andi a0, 0x3ff /* a0 <- node/core */
PTR_LA t0, nlm_early_init_secondary
jalr t0
diff --git a/arch/mips/ralink/prom.c b/arch/mips/ralink/prom.c
index 39a9142f71be..7ecb4af79b7b 100644
--- a/arch/mips/ralink/prom.c
+++ b/arch/mips/ralink/prom.c
@@ -30,8 +30,10 @@ const char *get_system_type(void)
return soc_info.sys_type;
}
-static __init void prom_init_cmdline(int argc, char **argv)
+static __init void prom_init_cmdline(void)
{
+ int argc;
+ char **argv;
int i;
pr_debug("prom: fw_arg0=%08x fw_arg1=%08x fw_arg2=%08x fw_arg3=%08x\n",
@@ -60,14 +62,11 @@ static __init void prom_init_cmdline(int argc, char **argv)
void __init prom_init(void)
{
- int argc;
- char **argv;
-
prom_soc_init(&soc_info);
pr_info("SoC Type: %s\n", get_system_type());
- prom_init_cmdline(argc, argv);
+ prom_init_cmdline();
}
void __init prom_free_prom_memory(void)
diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c
index 844f5cd55c8f..15506a1ff22a 100644
--- a/arch/mips/ralink/rt288x.c
+++ b/arch/mips/ralink/rt288x.c
@@ -40,16 +40,6 @@ static struct rt2880_pmx_group rt2880_pinmux_data_act[] = {
{ 0 }
};
-static void rt288x_wdt_reset(void)
-{
- u32 t;
-
- /* enable WDT reset output on pin SRAM_CS_N */
- t = rt_sysc_r32(SYSC_REG_CLKCFG);
- t |= CLKCFG_SRAM_CS_N_WDT;
- rt_sysc_w32(t, SYSC_REG_CLKCFG);
-}
-
void __init ralink_clk_init(void)
{
unsigned long cpu_rate, wmac_rate = 40000000;
diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c
index 9e4572592065..15b32cd01906 100644
--- a/arch/mips/ralink/rt305x.c
+++ b/arch/mips/ralink/rt305x.c
@@ -89,17 +89,6 @@ static struct rt2880_pmx_group rt5350_pinmux_data[] = {
{ 0 }
};
-static void rt305x_wdt_reset(void)
-{
- u32 t;
-
- /* enable WDT reset output on pin SRAM_CS_N */
- t = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG);
- t |= RT305X_SYSCFG_SRAM_CS0_MODE_WDT <<
- RT305X_SYSCFG_SRAM_CS0_MODE_SHIFT;
- rt_sysc_w32(t, SYSC_REG_SYSTEM_CONFIG);
-}
-
static unsigned long rt5350_get_mem_size(void)
{
void __iomem *sysc = (void __iomem *) KSEG1ADDR(RT305X_SYSC_BASE);
diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c
index 582995aaaf4e..f42834c7f007 100644
--- a/arch/mips/ralink/rt3883.c
+++ b/arch/mips/ralink/rt3883.c
@@ -63,16 +63,6 @@ static struct rt2880_pmx_group rt3883_pinmux_data[] = {
{ 0 }
};
-static void rt3883_wdt_reset(void)
-{
- u32 t;
-
- /* enable WDT reset output on GPIO 2 */
- t = rt_sysc_r32(RT3883_SYSC_REG_SYSCFG1);
- t |= RT3883_SYSCFG1_GPIO2_AS_WDT_OUT;
- rt_sysc_w32(t, RT3883_SYSC_REG_SYSCFG1);
-}
-
void __init ralink_clk_init(void)
{
unsigned long cpu_rate, sys_rate;
diff --git a/arch/mips/sgi-ip22/Platform b/arch/mips/sgi-ip22/Platform
index b7a4b7e04c38..e8f6b3a42a48 100644
--- a/arch/mips/sgi-ip22/Platform
+++ b/arch/mips/sgi-ip22/Platform
@@ -25,7 +25,7 @@ endif
# Simplified: what IP22 does at 128MB+ in ksegN, IP28 does at 512MB+ in xkphys
#
ifdef CONFIG_SGI_IP28
- ifeq ($(call cc-option-yn,-mr10k-cache-barrier=store), n)
+ ifeq ($(call cc-option-yn,-march=r10000 -mr10k-cache-barrier=store), n)
$(error gcc doesn't support needed option -mr10k-cache-barrier=store)
endif
endif
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index 05e804cdecaa..fdf48785d3e9 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -227,8 +227,10 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
rcu_read_lock();
bp = __this_cpu_read(bp_per_reg);
- if (!bp)
+ if (!bp) {
+ rc = NOTIFY_DONE;
goto out;
+ }
info = counter_arch_bp(bp);
/*
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index dc885b30f7a6..4014881e9843 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -1806,8 +1806,6 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
goto instr_done;
case LARX:
- if (regs->msr & MSR_LE)
- return 0;
if (op.ea & (size - 1))
break; /* can't handle misaligned */
err = -EFAULT;
@@ -1829,8 +1827,6 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
goto ldst_done;
case STCX:
- if (regs->msr & MSR_LE)
- return 0;
if (op.ea & (size - 1))
break; /* can't handle misaligned */
err = -EFAULT;
@@ -1854,8 +1850,6 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
goto ldst_done;
case LOAD:
- if (regs->msr & MSR_LE)
- return 0;
err = read_mem(&regs->gpr[op.reg], op.ea, size, regs);
if (!err) {
if (op.type & SIGNEXT)
@@ -1867,8 +1861,6 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
#ifdef CONFIG_PPC_FPU
case LOAD_FP:
- if (regs->msr & MSR_LE)
- return 0;
if (size == 4)
err = do_fp_load(op.reg, do_lfs, op.ea, size, regs);
else
@@ -1877,15 +1869,11 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
#endif
#ifdef CONFIG_ALTIVEC
case LOAD_VMX:
- if (regs->msr & MSR_LE)
- return 0;
err = do_vec_load(op.reg, do_lvx, op.ea & ~0xfUL, regs);
goto ldst_done;
#endif
#ifdef CONFIG_VSX
case LOAD_VSX:
- if (regs->msr & MSR_LE)
- return 0;
err = do_vsx_load(op.reg, do_lxvd2x, op.ea, regs);
goto ldst_done;
#endif
@@ -1908,8 +1896,6 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
goto instr_done;
case STORE:
- if (regs->msr & MSR_LE)
- return 0;
if ((op.type & UPDATE) && size == sizeof(long) &&
op.reg == 1 && op.update_reg == 1 &&
!(regs->msr & MSR_PR) &&
@@ -1922,8 +1908,6 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
#ifdef CONFIG_PPC_FPU
case STORE_FP:
- if (regs->msr & MSR_LE)
- return 0;
if (size == 4)
err = do_fp_store(op.reg, do_stfs, op.ea, size, regs);
else
@@ -1932,15 +1916,11 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
#endif
#ifdef CONFIG_ALTIVEC
case STORE_VMX:
- if (regs->msr & MSR_LE)
- return 0;
err = do_vec_store(op.reg, do_stvx, op.ea & ~0xfUL, regs);
goto ldst_done;
#endif
#ifdef CONFIG_VSX
case STORE_VSX:
- if (regs->msr & MSR_LE)
- return 0;
err = do_vsx_store(op.reg, do_stxvd2x, op.ea, regs);
goto ldst_done;
#endif
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index c1ea67db8404..c61ed7890cef 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -74,7 +74,8 @@ extern void execve_tail(void);
* User space process size: 2GB for 31 bit, 4TB or 8PT for 64 bit.
*/
-#define TASK_SIZE_OF(tsk) ((tsk)->mm->context.asce_limit)
+#define TASK_SIZE_OF(tsk) ((tsk)->mm ? \
+ (tsk)->mm->context.asce_limit : TASK_MAX_SIZE)
#define TASK_UNMAPPED_BASE (test_thread_flag(TIF_31BIT) ? \
(1UL << 30) : (1UL << 41))
#define TASK_SIZE TASK_SIZE_OF(current)
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
index 171e09bb8ea2..f7c3a61040bd 100644
--- a/arch/s390/kernel/crash_dump.c
+++ b/arch/s390/kernel/crash_dump.c
@@ -23,6 +23,8 @@
#define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
#define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y))))
+#define LINUX_NOTE_NAME "LINUX"
+
static struct memblock_region oldmem_region;
static struct memblock_type oldmem_type = {
@@ -312,7 +314,7 @@ static void *nt_fpregset(void *ptr, struct save_area *sa)
static void *nt_s390_timer(void *ptr, struct save_area *sa)
{
return nt_init(ptr, NT_S390_TIMER, &sa->timer, sizeof(sa->timer),
- KEXEC_CORE_NOTE_NAME);
+ LINUX_NOTE_NAME);
}
/*
@@ -321,7 +323,7 @@ static void *nt_s390_timer(void *ptr, struct save_area *sa)
static void *nt_s390_tod_cmp(void *ptr, struct save_area *sa)
{
return nt_init(ptr, NT_S390_TODCMP, &sa->clk_cmp,
- sizeof(sa->clk_cmp), KEXEC_CORE_NOTE_NAME);
+ sizeof(sa->clk_cmp), LINUX_NOTE_NAME);
}
/*
@@ -330,7 +332,7 @@ static void *nt_s390_tod_cmp(void *ptr, struct save_area *sa)
static void *nt_s390_tod_preg(void *ptr, struct save_area *sa)
{
return nt_init(ptr, NT_S390_TODPREG, &sa->tod_reg,
- sizeof(sa->tod_reg), KEXEC_CORE_NOTE_NAME);
+ sizeof(sa->tod_reg), LINUX_NOTE_NAME);
}
/*
@@ -339,7 +341,7 @@ static void *nt_s390_tod_preg(void *ptr, struct save_area *sa)
static void *nt_s390_ctrs(void *ptr, struct save_area *sa)
{
return nt_init(ptr, NT_S390_CTRS, &sa->ctrl_regs,
- sizeof(sa->ctrl_regs), KEXEC_CORE_NOTE_NAME);
+ sizeof(sa->ctrl_regs), LINUX_NOTE_NAME);
}
/*
@@ -348,7 +350,7 @@ static void *nt_s390_ctrs(void *ptr, struct save_area *sa)
static void *nt_s390_prefix(void *ptr, struct save_area *sa)
{
return nt_init(ptr, NT_S390_PREFIX, &sa->pref_reg,
- sizeof(sa->pref_reg), KEXEC_CORE_NOTE_NAME);
+ sizeof(sa->pref_reg), LINUX_NOTE_NAME);
}
/*
@@ -357,7 +359,7 @@ static void *nt_s390_prefix(void *ptr, struct save_area *sa)
static void *nt_s390_vx_high(void *ptr, __vector128 *vx_regs)
{
return nt_init(ptr, NT_S390_VXRS_HIGH, &vx_regs[16],
- 16 * sizeof(__vector128), KEXEC_CORE_NOTE_NAME);
+ 16 * sizeof(__vector128), LINUX_NOTE_NAME);
}
/*
@@ -370,12 +372,12 @@ static void *nt_s390_vx_low(void *ptr, __vector128 *vx_regs)
int i;
note = (Elf64_Nhdr *)ptr;
- note->n_namesz = strlen(KEXEC_CORE_NOTE_NAME) + 1;
+ note->n_namesz = strlen(LINUX_NOTE_NAME) + 1;
note->n_descsz = 16 * 8;
note->n_type = NT_S390_VXRS_LOW;
len = sizeof(Elf64_Nhdr);
- memcpy(ptr + len, KEXEC_CORE_NOTE_NAME, note->n_namesz);
+ memcpy(ptr + len, LINUX_NOTE_NAME, note->n_namesz);
len = roundup(len + note->n_namesz, 4);
ptr += len;
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 1f581eb61bc2..d097d71685df 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -805,10 +805,10 @@ static void __init setup_randomness(void)
{
struct sysinfo_3_2_2 *vmms;
- vmms = (struct sysinfo_3_2_2 *) alloc_page(GFP_KERNEL);
- if (vmms && stsi(vmms, 3, 2, 2) == 0 && vmms->count)
- add_device_randomness(&vmms, vmms->count);
- free_page((unsigned long) vmms);
+ vmms = (struct sysinfo_3_2_2 *) memblock_alloc(PAGE_SIZE, PAGE_SIZE);
+ if (stsi(vmms, 3, 2, 2) == 0 && vmms->count)
+ add_device_randomness(&vmms->vm, sizeof(vmms->vm[0]) * vmms->count);
+ memblock_free((unsigned long) vmms, PAGE_SIZE);
}
/*
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 575dc123bda2..23e3f5d77a24 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -295,6 +295,9 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
struct kvm_memory_slot *memslot;
int is_dirty = 0;
+ if (kvm_is_ucontrol(kvm))
+ return -EINVAL;
+
mutex_lock(&kvm->slots_lock);
r = -EINVAL;
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 8345ae1f117d..05ae254f84cf 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -1237,11 +1237,28 @@ EXPORT_SYMBOL_GPL(s390_reset_cmma);
*/
bool gmap_test_and_clear_dirty(unsigned long address, struct gmap *gmap)
{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
pte_t *pte;
spinlock_t *ptl;
bool dirty = false;
- pte = get_locked_pte(gmap->mm, address, &ptl);
+ pgd = pgd_offset(gmap->mm, address);
+ pud = pud_alloc(gmap->mm, pgd, address);
+ if (!pud)
+ return false;
+ pmd = pmd_alloc(gmap->mm, pud, address);
+ if (!pmd)
+ return false;
+ /* We can't run guests backed by huge pages, but userspace can
+ * still set them up and then try to migrate them without any
+ * migration support.
+ */
+ if (pmd_large(*pmd))
+ return true;
+
+ pte = pte_alloc_map_lock(gmap->mm, pmd, address, &ptl);
if (unlikely(!pte))
return false;
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index bb620df05d0d..3a7ae80dc49d 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -3499,7 +3499,7 @@ static void fix_rmode_seg(int seg, struct kvm_segment *save)
}
vmcs_write16(sf->selector, var.selector);
- vmcs_write32(sf->base, var.base);
+ vmcs_writel(sf->base, var.base);
vmcs_write32(sf->limit, var.limit);
vmcs_write32(sf->ar_bytes, vmx_segment_access_rights(&var));
}
@@ -4867,6 +4867,12 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
if (vmx_xsaves_supported())
vmcs_write64(XSS_EXIT_BITMAP, VMX_XSS_EXIT_BITMAP);
+ if (enable_pml) {
+ ASSERT(vmx->pml_pg);
+ vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg));
+ vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
+ }
+
return 0;
}
@@ -7839,22 +7845,6 @@ static void vmx_get_exit_info(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2)
*info2 = vmcs_read32(VM_EXIT_INTR_INFO);
}
-static int vmx_create_pml_buffer(struct vcpu_vmx *vmx)
-{
- struct page *pml_pg;
-
- pml_pg = alloc_page(GFP_KERNEL | __GFP_ZERO);
- if (!pml_pg)
- return -ENOMEM;
-
- vmx->pml_pg = pml_pg;
-
- vmcs_write64(PML_ADDRESS, page_to_phys(vmx->pml_pg));
- vmcs_write16(GUEST_PML_INDEX, PML_ENTITY_NUM - 1);
-
- return 0;
-}
-
static void vmx_destroy_pml_buffer(struct vcpu_vmx *vmx)
{
if (vmx->pml_pg) {
@@ -7915,7 +7905,7 @@ static void kvm_flush_pml_buffers(struct kvm *kvm)
static void vmx_dump_sel(char *name, uint32_t sel)
{
pr_err("%s sel=0x%04x, attr=0x%05x, limit=0x%08x, base=0x%016lx\n",
- name, vmcs_read32(sel),
+ name, vmcs_read16(sel),
vmcs_read32(sel + GUEST_ES_AR_BYTES - GUEST_ES_SELECTOR),
vmcs_read32(sel + GUEST_ES_LIMIT - GUEST_ES_SELECTOR),
vmcs_readl(sel + GUEST_ES_BASE - GUEST_ES_SELECTOR));
@@ -8789,14 +8779,26 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
if (err)
goto free_vcpu;
+ err = -ENOMEM;
+
+ /*
+ * If PML is turned on, failure on enabling PML just results in failure
+ * of creating the vcpu, therefore we can simplify PML logic (by
+ * avoiding dealing with cases, such as enabling PML partially on vcpus
+ * for the guest, etc.
+ */
+ if (enable_pml) {
+ vmx->pml_pg = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!vmx->pml_pg)
+ goto uninit_vcpu;
+ }
+
vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
BUILD_BUG_ON(ARRAY_SIZE(vmx_msr_index) * sizeof(vmx->guest_msrs[0])
> PAGE_SIZE);
- err = -ENOMEM;
- if (!vmx->guest_msrs) {
- goto uninit_vcpu;
- }
+ if (!vmx->guest_msrs)
+ goto free_pml;
vmx->loaded_vmcs = &vmx->vmcs01;
vmx->loaded_vmcs->vmcs = alloc_vmcs();
@@ -8840,18 +8842,6 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
vmx->nested.current_vmptr = -1ull;
vmx->nested.current_vmcs12 = NULL;
- /*
- * If PML is turned on, failure on enabling PML just results in failure
- * of creating the vcpu, therefore we can simplify PML logic (by
- * avoiding dealing with cases, such as enabling PML partially on vcpus
- * for the guest, etc.
- */
- if (enable_pml) {
- err = vmx_create_pml_buffer(vmx);
- if (err)
- goto free_vmcs;
- }
-
return &vmx->vcpu;
free_vmcs:
@@ -8859,6 +8849,8 @@ free_vmcs:
free_loaded_vmcs(vmx->loaded_vmcs);
free_msrs:
kfree(vmx->guest_msrs);
+free_pml:
+ vmx_destroy_pml_buffer(vmx);
uninit_vcpu:
kvm_vcpu_uninit(&vmx->vcpu);
free_vcpu:
diff --git a/arch/x86/platform/goldfish/goldfish.c b/arch/x86/platform/goldfish/goldfish.c
index 1693107a518e..0d17c0aafeb1 100644
--- a/arch/x86/platform/goldfish/goldfish.c
+++ b/arch/x86/platform/goldfish/goldfish.c
@@ -42,10 +42,22 @@ static struct resource goldfish_pdev_bus_resources[] = {
}
};
+static bool goldfish_enable __initdata;
+
+static int __init goldfish_setup(char *str)
+{
+ goldfish_enable = true;
+ return 0;
+}
+__setup("goldfish", goldfish_setup);
+
static int __init goldfish_init(void)
{
+ if (!goldfish_enable)
+ return -ENODEV;
+
platform_device_register_simple("goldfish_pdev_bus", -1,
- goldfish_pdev_bus_resources, 2);
+ goldfish_pdev_bus_resources, 2);
return 0;
}
device_initcall(goldfish_init);
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
index 9735691f37f1..49ccbd9022f6 100644
--- a/arch/xtensa/kernel/setup.c
+++ b/arch/xtensa/kernel/setup.c
@@ -133,6 +133,8 @@ static int __init parse_tag_initrd(const bp_tag_t* tag)
__tagtable(BP_TAG_INITRD, parse_tag_initrd);
+#endif /* CONFIG_BLK_DEV_INITRD */
+
#ifdef CONFIG_OF
static int __init parse_tag_fdt(const bp_tag_t *tag)
@@ -145,8 +147,6 @@ __tagtable(BP_TAG_FDT, parse_tag_fdt);
#endif /* CONFIG_OF */
-#endif /* CONFIG_BLK_DEV_INITRD */
-
static int __init parse_tag_cmdline(const bp_tag_t* tag)
{
strlcpy(command_line, (char *)(tag->data), COMMAND_LINE_SIZE);
diff --git a/block/blk-core.c b/block/blk-core.c
index 4162327d8804..500447be3db4 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -609,8 +609,6 @@ void blk_cleanup_queue(struct request_queue *q)
q->queue_lock = &q->__queue_lock;
spin_unlock_irq(lock);
- bdi_unregister(&q->backing_dev_info);
-
/* @q is and will stay empty, shutdown and put */
blk_put_queue(q);
}
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 40a0364fe183..8bd548378822 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -1259,12 +1259,9 @@ static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio)
blk_queue_split(q, &bio, q->bio_split);
- if (!is_flush_fua && !blk_queue_nomerges(q)) {
- if (blk_attempt_plug_merge(q, bio, &request_count,
- &same_queue_rq))
- return BLK_QC_T_NONE;
- } else
- request_count = blk_plug_queued_count(q);
+ if (!is_flush_fua && !blk_queue_nomerges(q) &&
+ blk_attempt_plug_merge(q, bio, &request_count, &same_queue_rq))
+ return BLK_QC_T_NONE;
rq = blk_mq_map_request(q, bio, &data);
if (unlikely(!rq))
@@ -1355,9 +1352,11 @@ static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio)
blk_queue_split(q, &bio, q->bio_split);
- if (!is_flush_fua && !blk_queue_nomerges(q) &&
- blk_attempt_plug_merge(q, bio, &request_count, NULL))
- return BLK_QC_T_NONE;
+ if (!is_flush_fua && !blk_queue_nomerges(q)) {
+ if (blk_attempt_plug_merge(q, bio, &request_count, NULL))
+ return BLK_QC_T_NONE;
+ } else
+ request_count = blk_plug_queued_count(q);
rq = blk_mq_map_request(q, bio, &data);
if (unlikely(!rq))
diff --git a/block/genhd.c b/block/genhd.c
index fad9db981675..dae7c9ed87e5 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -656,6 +656,11 @@ void del_gendisk(struct gendisk *disk)
disk->flags &= ~GENHD_FL_UP;
sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
+ /*
+ * Unregister bdi before releasing device numbers (as they can get
+ * reused and we'd get clashes in sysfs).
+ */
+ bdi_unregister(&disk->queue->backing_dev_info);
blk_unregister_queue(disk);
blk_unregister_region(disk_devt(disk), disk->minors);
diff --git a/crypto/Makefile b/crypto/Makefile
index 82fbff180ad3..03e66097eb0c 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_CRYPTO_SHA1) += sha1_generic.o
obj-$(CONFIG_CRYPTO_SHA256) += sha256_generic.o
obj-$(CONFIG_CRYPTO_SHA512) += sha512_generic.o
obj-$(CONFIG_CRYPTO_WP512) += wp512.o
+CFLAGS_wp512.o := $(call cc-option,-fno-schedule-insns) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149
obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o
obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o
obj-$(CONFIG_CRYPTO_ECB) += ecb.o
@@ -85,6 +86,7 @@ obj-$(CONFIG_CRYPTO_BLOWFISH_COMMON) += blowfish_common.o
obj-$(CONFIG_CRYPTO_TWOFISH) += twofish_generic.o
obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o
obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o
+CFLAGS_serpent_generic.o := $(call cc-option,-fsched-pressure) # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79149
obj-$(CONFIG_CRYPTO_AES) += aes_generic.o
obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o
obj-$(CONFIG_CRYPTO_CAST_COMMON) += cast_common.o
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index da0a8fd765f4..0e02c60a57b6 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -21778,7 +21778,7 @@ static struct aead_testvec aes_ccm_enc_tv_template[] = {
"\x09\x75\x9a\x9b\x3c\x9b\x27\x39",
.klen = 32,
.iv = "\x03\xf9\xd9\x4e\x63\xb5\x3d\x9d"
- "\x43\xf6\x1e\x50",
+ "\x43\xf6\x1e\x50\0\0\0\0",
.assoc = "\x57\xf5\x6b\x8b\x57\x5c\x3d\x3b"
"\x13\x02\x01\x0c\x83\x4c\x96\x35"
"\x8e\xd6\x39\xcf\x7d\x14\x9b\x94"
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
index c097f477c74c..14c2a07c9f3f 100644
--- a/drivers/acpi/nfit.c
+++ b/drivers/acpi/nfit.c
@@ -965,7 +965,7 @@ static size_t sizeof_nfit_set_info(int num_mappings)
+ num_mappings * sizeof(struct nfit_set_info_map);
}
-static int cmp_map(const void *m0, const void *m1)
+static int cmp_map_compat(const void *m0, const void *m1)
{
const struct nfit_set_info_map *map0 = m0;
const struct nfit_set_info_map *map1 = m1;
@@ -974,6 +974,14 @@ static int cmp_map(const void *m0, const void *m1)
sizeof(u64));
}
+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;
+}
+
/* Retrieve the nth entry referencing this spa */
static struct acpi_nfit_memory_map *memdev_from_spa(
struct acpi_nfit_desc *acpi_desc, u16 range_index, int n)
@@ -1029,6 +1037,12 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
cmp_map, NULL);
nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
+
+ /* support namespaces created with the wrong sort order */
+ sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
+ cmp_map_compat, NULL);
+ nd_set->altcookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
+
ndr_desc->nd_set = nd_set;
devm_kfree(dev, info);
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 59d8d0d14824..327f9e374b44 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -640,8 +640,11 @@ static int bcma_device_probe(struct device *dev)
drv);
int err = 0;
+ get_device(dev);
if (adrv->probe)
err = adrv->probe(core);
+ if (err)
+ put_device(dev);
return err;
}
@@ -654,6 +657,7 @@ static int bcma_device_remove(struct device *dev)
if (adrv->remove)
adrv->remove(core);
+ put_device(dev);
return 0;
}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index ab0b2dd3f629..cec36d5c24f5 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1108,9 +1108,12 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE)
return -EINVAL;
+ /* I/O need to be drained during transfer transition */
+ blk_mq_freeze_queue(lo->lo_queue);
+
err = loop_release_xfer(lo);
if (err)
- return err;
+ goto exit;
if (info->lo_encrypt_type) {
unsigned int type = info->lo_encrypt_type;
@@ -1125,12 +1128,14 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
err = loop_init_xfer(lo, xfer, info);
if (err)
- return err;
+ goto exit;
if (lo->lo_offset != info->lo_offset ||
lo->lo_sizelimit != info->lo_sizelimit)
- if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit))
- return -EFBIG;
+ if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) {
+ err = -EFBIG;
+ goto exit;
+ }
loop_config_discard(lo);
@@ -1148,13 +1153,6 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
(info->lo_flags & LO_FLAGS_AUTOCLEAR))
lo->lo_flags ^= LO_FLAGS_AUTOCLEAR;
- if ((info->lo_flags & LO_FLAGS_PARTSCAN) &&
- !(lo->lo_flags & LO_FLAGS_PARTSCAN)) {
- lo->lo_flags |= LO_FLAGS_PARTSCAN;
- lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN;
- loop_reread_partitions(lo, lo->lo_device);
- }
-
lo->lo_encrypt_key_size = info->lo_encrypt_key_size;
lo->lo_init[0] = info->lo_init[0];
lo->lo_init[1] = info->lo_init[1];
@@ -1167,7 +1165,17 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
/* update dio if lo_offset or transfer is changed */
__loop_update_dio(lo, lo->use_dio);
- return 0;
+ exit:
+ blk_mq_unfreeze_queue(lo->lo_queue);
+
+ if (!err && (info->lo_flags & LO_FLAGS_PARTSCAN) &&
+ !(lo->lo_flags & LO_FLAGS_PARTSCAN)) {
+ lo->lo_flags |= LO_FLAGS_PARTSCAN;
+ lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN;
+ loop_reread_partitions(lo, lo->lo_device);
+ }
+
+ return err;
}
static int
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 0beaa52df66b..5df8e1234505 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -94,6 +94,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x04CA, 0x300f) },
{ USB_DEVICE(0x04CA, 0x3010) },
{ USB_DEVICE(0x04CA, 0x3014) },
+ { USB_DEVICE(0x04CA, 0x3018) },
{ USB_DEVICE(0x0930, 0x0219) },
{ USB_DEVICE(0x0930, 0x021c) },
{ USB_DEVICE(0x0930, 0x0220) },
@@ -160,6 +161,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3014), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04ca, 0x3018), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index c306b483de60..cd6b141b9825 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -208,6 +208,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x04ca, 0x3014), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04ca, 0x3018), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index b861d5f32d03..ca7dd88048ac 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-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
@@ -72,6 +72,7 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf,
"Uses Device Tree: %d\n"
"Apps Supports Separate CMDRSP: %d\n"
"Apps Supports HDLC Encoding: %d\n"
+ "Apps Supports Header Untagging: %d\n"
"Apps Supports Sockets: %d\n"
"Logging Mode: %d\n"
"RSP Buffer is Busy: %d\n"
@@ -86,6 +87,7 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf,
driver->use_device_tree,
driver->supports_separate_cmdrsp,
driver->supports_apps_hdlc_encoding,
+ driver->supports_apps_header_untagging,
driver->supports_sockets,
driver->logging_mode,
driver->rsp_buf_busy,
@@ -97,18 +99,19 @@ static ssize_t diag_dbgfs_read_status(struct file *file, char __user *ubuf,
for (i = 0; i < NUM_PERIPHERALS; i++) {
ret += scnprintf(buf+ret, buf_size-ret,
- "p: %s Feature: %02x %02x |%c%c%c%c%c%c%c%c|\n",
+ "p: %s Feature: %02x %02x |%c%c%c%c%c%c%c%c%c|\n",
PERIPHERAL_STRING(i),
driver->feature[i].feature_mask[0],
driver->feature[i].feature_mask[1],
driver->feature[i].rcvd_feature_mask ? 'F':'f',
+ driver->feature[i].peripheral_buffering ? 'B':'b',
driver->feature[i].separate_cmd_rsp ? 'C':'c',
driver->feature[i].encode_hdlc ? 'H':'h',
- driver->feature[i].peripheral_buffering ? 'B':'b',
driver->feature[i].mask_centralization ? 'M':'m',
driver->feature[i].stm_support ? 'Q':'q',
driver->feature[i].sockets_enabled ? 'S':'s',
- driver->feature[i].sent_feature_mask ? 'T':'t');
+ driver->feature[i].sent_feature_mask ? 'T':'t',
+ driver->feature[i].untag_header ? 'U':'u');
}
#ifdef CONFIG_DIAG_OVER_USB
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index 44e71a704e6a..0c958d855f94 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -456,6 +456,8 @@ static void diag_send_feature_mask_update(uint8_t peripheral)
DIAG_SET_FEATURE_MASK(F_DIAG_REQ_RSP_SUPPORT);
if (driver->supports_apps_hdlc_encoding)
DIAG_SET_FEATURE_MASK(F_DIAG_APPS_HDLC_ENCODE);
+ if (driver->supports_apps_header_untagging)
+ DIAG_SET_FEATURE_MASK(F_DIAG_PKT_HEADER_UNTAG);
DIAG_SET_FEATURE_MASK(F_DIAG_MASK_CENTRALIZATION);
if (driver->supports_sockets)
DIAG_SET_FEATURE_MASK(F_DIAG_SOCKETS_ENABLED);
diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c
index c552f263d7e5..dc3029cc459d 100644
--- a/drivers/char/diag/diag_memorydevice.c
+++ b/drivers/char/diag/diag_memorydevice.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -29,6 +29,7 @@
#include "diagmem.h"
#include "diagfwd.h"
#include "diagfwd_peripheral.h"
+#include "diag_ipc_logging.h"
struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = {
{
@@ -143,9 +144,24 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx)
if (!buf || len < 0)
return -EINVAL;
- peripheral = GET_BUF_PERIPHERAL(ctx);
- if (peripheral > NUM_PERIPHERALS)
- return -EINVAL;
+ if (driver->pd_logging_mode) {
+ peripheral = GET_PD_CTXT(ctx);
+ switch (peripheral) {
+ case UPD_WLAN:
+ break;
+ case DIAG_ID_MPSS:
+ default:
+ peripheral = GET_BUF_PERIPHERAL(ctx);
+ if (peripheral > NUM_PERIPHERALS)
+ return -EINVAL;
+ break;
+ }
+ } else {
+ /* Account for Apps data as well */
+ peripheral = GET_BUF_PERIPHERAL(ctx);
+ if (peripheral > NUM_PERIPHERALS)
+ return -EINVAL;
+ }
session_info = diag_md_session_get_peripheral(peripheral);
if (!session_info)
@@ -219,18 +235,41 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size,
uint8_t peripheral = 0;
struct diag_md_session_t *session_info = NULL;
+ mutex_lock(&driver->diagfwd_untag_mutex);
+
for (i = 0; i < NUM_DIAG_MD_DEV && !err; i++) {
ch = &diag_md[i];
for (j = 0; j < ch->num_tbl_entries && !err; j++) {
entry = &ch->tbl[j];
if (entry->len <= 0)
continue;
- peripheral = GET_BUF_PERIPHERAL(entry->ctx);
- /* Account for Apps data as well */
- if (peripheral > NUM_PERIPHERALS)
- goto drop_data;
+ if (driver->pd_logging_mode) {
+ peripheral = GET_PD_CTXT(entry->ctx);
+ switch (peripheral) {
+ case UPD_WLAN:
+ break;
+ case DIAG_ID_MPSS:
+ default:
+ peripheral =
+ GET_BUF_PERIPHERAL(entry->ctx);
+ if (peripheral > NUM_PERIPHERALS)
+ goto drop_data;
+ break;
+ }
+ } else {
+ /* Account for Apps data as well */
+ peripheral = GET_BUF_PERIPHERAL(entry->ctx);
+ if (peripheral > NUM_PERIPHERALS)
+ goto drop_data;
+ }
+
session_info =
diag_md_session_get_peripheral(peripheral);
+ if (!session_info) {
+ mutex_unlock(&driver->diagfwd_untag_mutex);
+ return -EIO;
+ }
+
if (session_info && info &&
(session_info->pid != info->pid))
continue;
@@ -303,6 +342,8 @@ drop_data:
if (drain_again)
chk_logging_wakeup();
+ mutex_unlock(&driver->diagfwd_untag_mutex);
+
return err;
}
@@ -322,7 +363,8 @@ int diag_md_close_peripheral(int id, uint8_t peripheral)
spin_lock_irqsave(&ch->lock, flags);
for (i = 0; i < ch->num_tbl_entries && !found; i++) {
entry = &ch->tbl[i];
- if (GET_BUF_PERIPHERAL(entry->ctx) != peripheral)
+ if ((GET_BUF_PERIPHERAL(entry->ctx) != peripheral) ||
+ (GET_PD_CTXT(entry->ctx) != peripheral))
continue;
found = 1;
if (ch->ops && ch->ops->write_done) {
diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c
index 6586f5e0cf86..55c5de1ea9fc 100644
--- a/drivers/char/diag/diag_mux.c
+++ b/drivers/char/diag/diag_mux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -133,21 +133,43 @@ int diag_mux_queue_read(int proc)
int diag_mux_write(int proc, unsigned char *buf, int len, int ctx)
{
struct diag_logger_t *logger = NULL;
- int peripheral;
+ int peripheral, upd;
if (proc < 0 || proc >= NUM_MUX_PROC)
return -EINVAL;
if (!diag_mux)
return -EIO;
- peripheral = GET_BUF_PERIPHERAL(ctx);
- if (peripheral > NUM_PERIPHERALS)
- return -EINVAL;
-
- if (MD_PERIPHERAL_MASK(peripheral) & diag_mux->mux_mask)
- logger = diag_mux->md_ptr;
- else
- logger = diag_mux->usb_ptr;
+ upd = GET_PD_CTXT(ctx);
+ if (upd) {
+ switch (upd) {
+ case DIAG_ID_MPSS:
+ upd = PERIPHERAL_MODEM;
+ break;
+ case UPD_WLAN:
+ break;
+ default:
+ pr_err("diag: invalid pd ctxt= %d\n", upd);
+ return -EINVAL;
+ }
+ if (((MD_PERIPHERAL_MASK(upd)) &
+ (diag_mux->mux_mask)) &&
+ driver->md_session_map[upd])
+ logger = diag_mux->md_ptr;
+ else
+ logger = diag_mux->usb_ptr;
+ } else {
+
+ peripheral = GET_BUF_PERIPHERAL(ctx);
+ if (peripheral > NUM_PERIPHERALS)
+ return -EINVAL;
+
+ if (MD_PERIPHERAL_MASK(peripheral) &
+ diag_mux->mux_mask)
+ logger = diag_mux->md_ptr;
+ else
+ logger = diag_mux->usb_ptr;
+ }
if (logger && logger->log_ops && logger->log_ops->write)
return logger->log_ops->write(proc, buf, len, ctx);
@@ -159,9 +181,17 @@ int diag_mux_close_peripheral(int proc, uint8_t peripheral)
struct diag_logger_t *logger = NULL;
if (proc < 0 || proc >= NUM_MUX_PROC)
return -EINVAL;
+
/* Peripheral should account for Apps data as well */
- if (peripheral > NUM_PERIPHERALS)
- return -EINVAL;
+ if (peripheral > NUM_PERIPHERALS) {
+ if (driver->num_pd_session) {
+ if (peripheral > NUM_MD_SESSIONS)
+ return -EINVAL;
+ } else {
+ return -EINVAL;
+ }
+ }
+
if (!diag_mux)
return -EIO;
@@ -182,7 +212,8 @@ int diag_mux_switch_logging(int *req_mode, int *peripheral_mask)
if (!req_mode)
return -EINVAL;
- if (*peripheral_mask <= 0 || *peripheral_mask > DIAG_CON_ALL) {
+ if (*peripheral_mask <= 0 ||
+ (*peripheral_mask > (DIAG_CON_ALL | DIAG_CON_UPD_ALL))) {
pr_err("diag: mask %d in %s\n", *peripheral_mask, __func__);
return -EINVAL;
}
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 9d235b7abc58..511b019e33ec 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -64,14 +64,19 @@
#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */
#define DIAG_CON_WCNSS (0x0008) /* Bit mask for WCNSS */
#define DIAG_CON_SENSORS (0x0010) /* Bit mask for Sensors */
-#define DIAG_CON_WDSP (0x0020) /* Bit mask for WDSP */
-#define DIAG_CON_CDSP (0x0040)
+#define DIAG_CON_WDSP (0x0020) /* Bit mask for WDSP */
+#define DIAG_CON_CDSP (0x0040) /* Bit mask for CDSP */
+
+#define DIAG_CON_UPD_WLAN (0x1000) /*Bit mask for WLAN PD*/
+#define DIAG_CON_UPD_AUDIO (0x2000) /*Bit mask for AUDIO PD*/
+#define DIAG_CON_UPD_SENSORS (0x4000) /*Bit mask for SENSORS PD*/
#define DIAG_CON_NONE (0x0000) /* Bit mask for No SS*/
#define DIAG_CON_ALL (DIAG_CON_APSS | DIAG_CON_MPSS \
| DIAG_CON_LPASS | DIAG_CON_WCNSS \
| DIAG_CON_SENSORS | DIAG_CON_WDSP \
| DIAG_CON_CDSP)
+#define DIAG_CON_UPD_ALL (DIAG_CON_UPD_WLAN)
#define DIAG_STM_MODEM 0x01
#define DIAG_STM_LPASS 0x02
@@ -165,7 +170,7 @@
#define PKT_ALLOC 1
#define PKT_RESET 2
-#define FEATURE_MASK_LEN 2
+#define FEATURE_MASK_LEN 4
#define DIAG_MD_NONE 0
#define DIAG_MD_PERIPHERAL 1
@@ -209,8 +214,18 @@
#define NUM_PERIPHERALS 6
#define APPS_DATA (NUM_PERIPHERALS)
+#define UPD_WLAN 7
+#define UPD_AUDIO 8
+#define UPD_SENSORS 9
+#define NUM_UPD 3
+
+#define DIAG_ID_APPS 1
+#define DIAG_ID_MPSS 2
+#define DIAG_ID_WLAN 3
+
/* Number of sessions possible in Memory Device Mode. +1 for Apps data */
-#define NUM_MD_SESSIONS (NUM_PERIPHERALS + 1)
+#define NUM_MD_SESSIONS (NUM_PERIPHERALS \
+ + NUM_UPD + 1)
#define MD_PERIPHERAL_MASK(x) (1 << x)
@@ -407,6 +422,7 @@ struct diag_partial_pkt_t {
struct diag_logging_mode_param_t {
uint32_t req_mode;
uint32_t peripheral_mask;
+ uint32_t pd_mask;
uint8_t mode_param;
} __packed;
@@ -418,6 +434,7 @@ struct diag_md_session_t {
struct diag_mask_info *msg_mask;
struct diag_mask_info *log_mask;
struct diag_mask_info *event_mask;
+ struct thread_info *md_client_thread_info;
struct task_struct *task;
};
@@ -453,6 +470,7 @@ struct diag_feature_t {
uint8_t log_on_demand;
uint8_t separate_cmd_rsp;
uint8_t encode_hdlc;
+ uint8_t untag_header;
uint8_t peripheral_buffering;
uint8_t mask_centralization;
uint8_t stm_support;
@@ -484,6 +502,7 @@ struct diagchar_dev {
int use_device_tree;
int supports_separate_cmdrsp;
int supports_apps_hdlc_encoding;
+ int supports_apps_header_untagging;
int supports_sockets;
/* The state requested in the STM command */
int stm_state_requested[NUM_STM_PROCESSORS];
@@ -515,6 +534,7 @@ struct diagchar_dev {
struct mutex cmd_reg_mutex;
uint32_t cmd_reg_count;
struct mutex diagfwd_channel_mutex[NUM_PERIPHERALS];
+ struct mutex diagfwd_untag_mutex;
/* Sizes that reflect memory pool sizes */
unsigned int poolsize;
unsigned int poolsize_hdlc;
@@ -577,6 +597,10 @@ struct diagchar_dev {
int in_busy_dcipktdata;
int logging_mode;
int logging_mask;
+ int pd_logging_mode;
+ int num_pd_session;
+ int cpd_len_1;
+ int cpd_len_2;
int mask_check;
uint32_t md_session_mask;
uint8_t md_session_mode;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 335064352789..4f56696f52e9 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -395,7 +395,8 @@ static uint32_t diag_translate_kernel_to_user_mask(uint32_t peripheral_mask)
ret |= DIAG_CON_WDSP;
if (peripheral_mask & MD_PERIPHERAL_MASK(PERIPHERAL_CDSP))
ret |= DIAG_CON_CDSP;
-
+ if (peripheral_mask & MD_PERIPHERAL_MASK(UPD_WLAN))
+ ret |= DIAG_CON_UPD_WLAN;
return ret;
}
int diag_mask_param(void)
@@ -453,6 +454,14 @@ static void diag_close_logging_process(const int pid)
params.mode_param = 0;
params.peripheral_mask =
diag_translate_kernel_to_user_mask(session_peripheral_mask);
+ if (driver->pd_logging_mode)
+ params.pd_mask =
+ diag_translate_kernel_to_user_mask(session_peripheral_mask);
+
+ if (session_peripheral_mask & MD_PERIPHERAL_MASK(UPD_WLAN)) {
+ driver->pd_logging_mode--;
+ driver->num_pd_session--;
+ }
mutex_lock(&driver->diagchar_mutex);
diag_switch_logging(&params);
mutex_unlock(&driver->diagchar_mutex);
@@ -1237,11 +1246,10 @@ int diag_md_session_create(int mode, int peripheral_mask, int proc)
mutex_unlock(&driver->md_session_lock);
return -ENOMEM;
}
-
new_session->peripheral_mask = 0;
new_session->pid = current->tgid;
new_session->task = current;
-
+ new_session->md_client_thread_info = current_thread_info();
new_session->log_mask = kzalloc(sizeof(struct diag_mask_info),
GFP_KERNEL);
if (!new_session->log_mask) {
@@ -1359,7 +1367,6 @@ static void diag_md_session_close(struct diag_md_session_t *session_info)
struct diag_md_session_t *diag_md_session_get_pid(int pid)
{
int i;
-
for (i = 0; i < NUM_MD_SESSIONS; i++) {
if (driver->md_session_map[i] &&
driver->md_session_map[i]->pid == pid)
@@ -1475,7 +1482,10 @@ static int diag_md_session_check(int curr_mode, int req_mode,
* If this session owns all the requested peripherals, then
* call function to switch the modes/masks for the md_session
*/
+ mutex_lock(&driver->md_session_lock);
session_info = diag_md_session_get_pid(current->tgid);
+ mutex_unlock(&driver->md_session_lock);
+
if (!session_info) {
*change_mode = 1;
return 0;
@@ -1504,7 +1514,9 @@ static int diag_md_session_check(int curr_mode, int req_mode,
* owned by this md session
*/
change_mask = driver->md_session_mask & param->peripheral_mask;
+ mutex_lock(&driver->md_session_lock);
session_info = diag_md_session_get_pid(current->tgid);
+ mutex_unlock(&driver->md_session_lock);
if (session_info) {
if ((session_info->peripheral_mask & change_mask)
@@ -1548,6 +1560,8 @@ static uint32_t diag_translate_mask(uint32_t peripheral_mask)
ret |= (1 << PERIPHERAL_WDSP);
if (peripheral_mask & DIAG_CON_CDSP)
ret |= (1 << PERIPHERAL_CDSP);
+ if (peripheral_mask & DIAG_CON_UPD_WLAN)
+ ret |= (1 << UPD_WLAN);
return ret;
}
@@ -1569,8 +1583,28 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param)
return -EINVAL;
}
- peripheral_mask = diag_translate_mask(param->peripheral_mask);
- param->peripheral_mask = peripheral_mask;
+ switch (param->pd_mask) {
+ case DIAG_CON_UPD_WLAN:
+ if (driver->md_session_map[PERIPHERAL_MODEM] &&
+ (MD_PERIPHERAL_MASK(PERIPHERAL_MODEM) &
+ diag_mux->mux_mask)) {
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "diag_fr: User PD is already logging onto active peripheral logging\n");
+ return -EINVAL;
+ }
+ peripheral_mask =
+ diag_translate_mask(param->pd_mask);
+ param->peripheral_mask = peripheral_mask;
+ driver->pd_logging_mode++;
+ driver->num_pd_session++;
+ break;
+
+ default:
+ peripheral_mask =
+ diag_translate_mask(param->peripheral_mask);
+ param->peripheral_mask = peripheral_mask;
+ break;
+ }
switch (param->req_mode) {
case CALLBACK_MODE:
@@ -1590,7 +1624,7 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param)
curr_mode = driver->logging_mode;
DIAG_LOG(DIAG_DEBUG_USERSPACE,
- "request to switch logging from %d mask:%0x to %d mask:%0x\n",
+ "request to switch logging from %d mask:%0x to new_mode %d mask:%0x\n",
curr_mode, driver->md_session_mask, new_mode, peripheral_mask);
err = diag_md_session_check(curr_mode, new_mode, param, &do_switch);
@@ -1892,8 +1926,9 @@ static int diag_ioctl_hdlc_toggle(unsigned long ioarg)
{
uint8_t hdlc_support;
struct diag_md_session_t *session_info = NULL;
-
+ mutex_lock(&driver->md_session_lock);
session_info = diag_md_session_get_pid(current->tgid);
+ mutex_unlock(&driver->md_session_lock);
if (copy_from_user(&hdlc_support, (void __user *)ioarg,
sizeof(uint8_t)))
return -EFAULT;
@@ -1910,6 +1945,27 @@ static int diag_ioctl_hdlc_toggle(unsigned long ioarg)
return 0;
}
+static int diag_ioctl_query_pd_logging(unsigned long ioarg)
+{
+ int ret = -EINVAL;
+
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "diag: %s: Untagging support on APPS is %s\n", __func__,
+ ((driver->supports_apps_header_untagging) ?
+ "present" : "absent"));
+
+ DIAG_LOG(DIAG_DEBUG_USERSPACE,
+ "diag: %s: Tagging support on MODEM is %s\n", __func__,
+ (driver->feature[PERIPHERAL_MODEM].untag_header ?
+ "present" : "absent"));
+
+ if (driver->supports_apps_header_untagging &&
+ driver->feature[PERIPHERAL_MODEM].untag_header)
+ ret = 0;
+
+ return ret;
+}
+
static int diag_ioctl_register_callback(unsigned long ioarg)
{
int err = 0;
@@ -2149,6 +2205,9 @@ long diagchar_compat_ioctl(struct file *filp,
case DIAG_IOCTL_HDLC_TOGGLE:
result = diag_ioctl_hdlc_toggle(ioarg);
break;
+ case DIAG_IOCTL_QUERY_PD_LOGGING:
+ result = diag_ioctl_query_pd_logging(ioarg);
+ break;
}
return result;
}
@@ -2272,6 +2331,9 @@ long diagchar_ioctl(struct file *filp,
case DIAG_IOCTL_HDLC_TOGGLE:
result = diag_ioctl_hdlc_toggle(ioarg);
break;
+ case DIAG_IOCTL_QUERY_PD_LOGGING:
+ result = diag_ioctl_query_pd_logging(ioarg);
+ break;
}
return result;
}
@@ -2603,7 +2665,9 @@ static int diag_user_process_raw_data(const char __user *buf, int len)
} else {
wait_event_interruptible(driver->wait_q,
(driver->in_busy_pktdata == 0));
+ mutex_lock(&driver->md_session_lock);
info = diag_md_session_get_pid(current->tgid);
+ mutex_unlock(&driver->md_session_lock);
ret = diag_process_apps_pkt(user_space_data, len, info);
if (ret == 1)
diag_send_error_rsp((void *)(user_space_data), len,
@@ -2671,7 +2735,9 @@ static int diag_user_process_userspace_data(const char __user *buf, int len)
/* send masks to local processor now */
if (!remote_proc) {
+ mutex_lock(&driver->md_session_lock);
session_info = diag_md_session_get_pid(current->tgid);
+ mutex_unlock(&driver->md_session_lock);
if (!session_info) {
pr_err("diag:In %s request came from invalid md session pid:%d",
__func__, current->tgid);
@@ -2832,7 +2898,9 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count,
COPY_USER_SPACE_OR_EXIT(buf, data_type, sizeof(int));
/* place holder for number of data field */
ret += sizeof(int);
+ mutex_lock(&driver->md_session_lock);
session_info = diag_md_session_get_pid(current->tgid);
+ mutex_unlock(&driver->md_session_lock);
exit_stat = diag_md_copy_to_user(buf, &ret, count,
session_info);
goto exit;
@@ -2846,7 +2914,9 @@ static ssize_t diagchar_read(struct file *file, char __user *buf, size_t count,
data_type = driver->data_ready[index] & HDLC_SUPPORT_TYPE;
driver->data_ready[index] ^= HDLC_SUPPORT_TYPE;
COPY_USER_SPACE_OR_EXIT(buf, data_type, sizeof(int));
+ mutex_lock(&driver->md_session_lock);
session_info = diag_md_session_get_pid(current->tgid);
+ mutex_unlock(&driver->md_session_lock);
if (session_info)
COPY_USER_SPACE_OR_EXIT(buf+4,
session_info->hdlc_disabled,
@@ -3275,7 +3345,7 @@ static void diag_debug_init(void)
* to be logged to IPC
*/
diag_debug_mask = DIAG_DEBUG_PERIPHERALS | DIAG_DEBUG_DCI |
- DIAG_DEBUG_BRIDGE;
+ DIAG_DEBUG_USERSPACE | DIAG_DEBUG_BRIDGE;
}
#else
static void diag_debug_init(void)
@@ -3404,6 +3474,8 @@ static int __init diagchar_init(void)
poolsize_usb_apps + 1 + (NUM_PERIPHERALS * 6));
driver->num_clients = max_clients;
driver->logging_mode = DIAG_USB_MODE;
+ driver->pd_logging_mode = 0;
+ driver->num_pd_session = 0;
driver->mask_check = 0;
driver->in_busy_pktdata = 0;
driver->in_busy_dcipktdata = 0;
@@ -3421,6 +3493,7 @@ static int __init diagchar_init(void)
mutex_init(&apps_data_mutex);
for (i = 0; i < NUM_PERIPHERALS; i++)
mutex_init(&driver->diagfwd_channel_mutex[i]);
+ mutex_init(&driver->diagfwd_untag_mutex);
init_waitqueue_head(&driver->wait_q);
INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn);
INIT_WORK(&(driver->update_user_clients),
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 99a16dd47cd4..532d2b149317 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -1587,6 +1587,7 @@ int diagfwd_init(void)
driver->real_time_mode[i] = 1;
driver->supports_separate_cmdrsp = 1;
driver->supports_apps_hdlc_encoding = 1;
+ driver->supports_apps_header_untagging = 1;
mutex_init(&driver->diag_hdlc_mutex);
mutex_init(&driver->diag_cntl_mutex);
mutex_init(&driver->mode_lock);
@@ -1616,6 +1617,8 @@ int diagfwd_init(void)
driver->feature[i].rcvd_feature_mask = 0;
driver->feature[i].peripheral_buffering = 0;
driver->feature[i].encode_hdlc = 0;
+ driver->feature[i].untag_header =
+ DISABLE_PKT_HEADER_UNTAGGING;
driver->feature[i].mask_centralization = 0;
driver->feature[i].log_on_demand = 0;
driver->feature[i].sent_feature_mask = 0;
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 4c6d86fc36ae..97ad3f60ba5e 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -19,9 +19,11 @@
*/
#define SET_BUF_CTXT(p, d, n) \
(((p & 0xFF) << 16) | ((d & 0xFF) << 8) | (n & 0xFF))
+#define SET_PD_CTXT(u) ((u & 0xFF) << 24)
#define GET_BUF_PERIPHERAL(p) ((p & 0xFF0000) >> 16)
#define GET_BUF_TYPE(d) ((d & 0x00FF00) >> 8)
#define GET_BUF_NUM(n) ((n & 0x0000FF))
+#define GET_PD_CTXT(u) ((u & 0xFF000000) >> 24)
#define CHK_OVERFLOW(bufStart, start, end, length) \
((((bufStart) <= (start)) && ((end) - (start) >= (length))) ? 1 : 0)
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 62c8d0028af9..ae749725f6db 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-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
@@ -124,7 +124,9 @@ void diag_notify_md_client(uint8_t peripheral, int data)
info.si_signo = SIGCONT;
if (driver->md_session_map[peripheral] &&
driver->md_session_map[peripheral]->task) {
- if (driver->md_session_map[peripheral]->pid ==
+ if (driver->md_session_map[peripheral]->
+ md_client_thread_info->task != NULL
+ && driver->md_session_map[peripheral]->pid ==
driver->md_session_map[peripheral]->task->tgid) {
DIAG_LOG(DIAG_DEBUG_PERIPHERALS,
"md_session %d pid = %d, md_session %d task tgid = %d\n",
@@ -198,6 +200,20 @@ static void process_hdlc_encoding_feature(uint8_t peripheral)
}
}
+static void process_upd_header_untagging_feature(uint8_t peripheral)
+{
+ if (peripheral >= NUM_PERIPHERALS)
+ return;
+
+ if (driver->supports_apps_header_untagging) {
+ driver->feature[peripheral].untag_header =
+ ENABLE_PKT_HEADER_UNTAGGING;
+ } else {
+ driver->feature[peripheral].untag_header =
+ DISABLE_PKT_HEADER_UNTAGGING;
+ }
+}
+
static void process_command_deregistration(uint8_t *buf, uint32_t len,
uint8_t peripheral)
{
@@ -374,6 +390,8 @@ static void process_incoming_feature_mask(uint8_t *buf, uint32_t len,
driver->feature[peripheral].separate_cmd_rsp = 1;
if (FEATURE_SUPPORTED(F_DIAG_APPS_HDLC_ENCODE))
process_hdlc_encoding_feature(peripheral);
+ if (FEATURE_SUPPORTED(F_DIAG_PKT_HEADER_UNTAG))
+ process_upd_header_untagging_feature(peripheral);
if (FEATURE_SUPPORTED(F_DIAG_STM))
enable_stm_feature(peripheral);
if (FEATURE_SUPPORTED(F_DIAG_MASK_CENTRALIZATION))
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index 7eed8ef8779e..e8608f47ff14 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-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
@@ -67,6 +67,7 @@
#define F_DIAG_MASK_CENTRALIZATION 11
#define F_DIAG_SOCKETS_ENABLED 13
#define F_DIAG_DCI_EXTENDED_HEADER_SUPPORT 14
+#define F_DIAG_PKT_HEADER_UNTAG 16
#define ENABLE_SEPARATE_CMDRSP 1
#define DISABLE_SEPARATE_CMDRSP 0
@@ -81,6 +82,9 @@
#define ENABLE_APPS_HDLC_ENCODING 1
#define DISABLE_APPS_HDLC_ENCODING 0
+#define ENABLE_PKT_HEADER_UNTAGGING 1
+#define DISABLE_PKT_HEADER_UNTAGGING 0
+
#define DIAG_MODE_PKT_LEN 36
struct diag_ctrl_pkt_header_t {
diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c
index b04008c8fec3..55d36abe4679 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -46,6 +46,8 @@ static void diagfwd_cntl_open(struct diagfwd_info *fwd_info);
static void diagfwd_cntl_close(struct diagfwd_info *fwd_info);
static void diagfwd_dci_open(struct diagfwd_info *fwd_info);
static void diagfwd_dci_close(struct diagfwd_info *fwd_info);
+static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
+ unsigned char *buf, int len);
static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
unsigned char *buf, int len);
static void diagfwd_cntl_read_done(struct diagfwd_info *fwd_info,
@@ -59,7 +61,7 @@ struct diagfwd_info peripheral_info[NUM_TYPES][NUM_PERIPHERALS];
static struct diag_channel_ops data_ch_ops = {
.open = NULL,
.close = NULL,
- .read_done = diagfwd_data_read_done
+ .read_done = diagfwd_data_read_untag_done
};
static struct diag_channel_ops cntl_ch_ops = {
@@ -214,6 +216,221 @@ static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len)
return buf->len;
}
+static void diagfwd_data_process_done(struct diagfwd_info *fwd_info,
+ struct diagfwd_buf_t *buf, int len)
+{
+ int err = 0;
+ int write_len = 0, peripheral = 0;
+ unsigned char *write_buf = NULL;
+ struct diag_md_session_t *session_info = NULL;
+ uint8_t hdlc_disabled = 0;
+
+ if (!fwd_info || !buf || len <= 0) {
+ diag_ws_release();
+ return;
+ }
+
+ switch (fwd_info->type) {
+ case TYPE_DATA:
+ case TYPE_CMD:
+ break;
+ default:
+ pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n",
+ __func__, fwd_info->type,
+ fwd_info->peripheral);
+ diag_ws_release();
+ return;
+ }
+
+ mutex_lock(&driver->hdlc_disable_mutex);
+ mutex_lock(&fwd_info->data_mutex);
+ peripheral = GET_PD_CTXT(buf->ctxt);
+ if (peripheral == DIAG_ID_MPSS)
+ peripheral = PERIPHERAL_MODEM;
+
+ session_info =
+ diag_md_session_get_peripheral(peripheral);
+ if (session_info)
+ hdlc_disabled = session_info->hdlc_disabled;
+ else
+ hdlc_disabled = driver->hdlc_disabled;
+
+ if (hdlc_disabled) {
+ /* The data is raw and and on APPS side HDLC is disabled */
+ if (!buf) {
+ pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
+ __func__, buf, fwd_info->peripheral,
+ fwd_info->type);
+ goto end;
+ }
+ if (len > PERIPHERAL_BUF_SZ) {
+ pr_err("diag: In %s, Incoming buffer too large %d, peripheral %d, type: %d\n",
+ __func__, len, fwd_info->peripheral,
+ fwd_info->type);
+ goto end;
+ }
+ write_len = len;
+ if (write_len <= 0)
+ goto end;
+ write_buf = buf->data_raw;
+ } else {
+ if (!buf) {
+ pr_err("diag: In %s, no match for non encode buffer %pK, peripheral %d, type: %d\n",
+ __func__, buf, fwd_info->peripheral,
+ fwd_info->type);
+ goto end;
+ }
+
+ write_len = check_bufsize_for_encoding(buf, len);
+ if (write_len <= 0) {
+ pr_err("diag: error in checking buf for encoding\n");
+ goto end;
+ }
+ write_buf = buf->data;
+ err = diag_add_hdlc_encoding(write_buf, &write_len,
+ buf->data_raw, len);
+ if (err) {
+ pr_err("diag: error in adding hdlc encoding\n");
+ goto end;
+ }
+ }
+
+ if (write_len > 0) {
+ err = diag_mux_write(DIAG_LOCAL_PROC, write_buf, write_len,
+ buf->ctxt);
+ if (err) {
+ pr_err_ratelimited("diag: In %s, unable to write to mux error: %d\n",
+ __func__, err);
+ goto end;
+ }
+ }
+ mutex_unlock(&fwd_info->data_mutex);
+ mutex_unlock(&driver->hdlc_disable_mutex);
+ diagfwd_queue_read(fwd_info);
+ return;
+
+end:
+ diag_ws_release();
+ mutex_unlock(&fwd_info->data_mutex);
+ mutex_unlock(&driver->hdlc_disable_mutex);
+ if (buf) {
+ diagfwd_write_done(fwd_info->peripheral, fwd_info->type,
+ GET_BUF_NUM(buf->ctxt));
+ }
+ diagfwd_queue_read(fwd_info);
+}
+
+static void diagfwd_data_read_untag_done(struct diagfwd_info *fwd_info,
+ unsigned char *buf, int len)
+{
+ int len_cpd = 0, len_upd_1 = 0;
+ int ctxt_cpd = 0, ctxt_upd_1 = 0;
+ int buf_len = 0, processed = 0;
+ unsigned char *temp_buf_main = NULL;
+ unsigned char *temp_buf_cpd = NULL;
+ unsigned char *temp_buf_upd_1 = NULL;
+ struct diagfwd_buf_t *temp_ptr_upd = NULL;
+ struct diagfwd_buf_t *temp_ptr_cpd = NULL;
+ int flag_buf_1 = 0, flag_buf_2 = 0;
+
+ if (!fwd_info || !buf || len <= 0) {
+ diag_ws_release();
+ return;
+ }
+
+ switch (fwd_info->type) {
+ case TYPE_DATA:
+ case TYPE_CMD:
+ break;
+ default:
+ pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n",
+ __func__, fwd_info->type,
+ fwd_info->peripheral);
+ diag_ws_release();
+ return;
+ }
+
+ if (driver->feature[fwd_info->peripheral].encode_hdlc &&
+ driver->feature[fwd_info->peripheral].untag_header) {
+ mutex_lock(&driver->diagfwd_untag_mutex);
+ temp_buf_cpd = buf;
+ temp_buf_main = buf;
+ if (fwd_info->buf_1 &&
+ fwd_info->buf_1->data_raw == buf) {
+ flag_buf_1 = 1;
+ if (fwd_info->type == TYPE_DATA)
+ temp_buf_upd_1 =
+ fwd_info->buf_upd_1_a->data_raw;
+ } else {
+ flag_buf_2 = 1;
+ if (fwd_info->type == TYPE_DATA)
+ temp_buf_upd_1 =
+ fwd_info->buf_upd_1_b->data_raw;
+ }
+ while (processed < len) {
+ buf_len =
+ *(uint16_t *) (temp_buf_main + 2);
+ switch ((*temp_buf_main)) {
+ case DIAG_ID_MPSS:
+ ctxt_cpd = DIAG_ID_MPSS;
+ len_cpd += buf_len;
+ if (temp_buf_cpd) {
+ memcpy(temp_buf_cpd,
+ (temp_buf_main + 4), buf_len);
+ temp_buf_cpd += buf_len;
+ }
+ break;
+ case DIAG_ID_WLAN:
+ ctxt_upd_1 = UPD_WLAN;
+ len_upd_1 += buf_len;
+ if (temp_buf_upd_1) {
+ memcpy(temp_buf_upd_1,
+ (temp_buf_main + 4), buf_len);
+ temp_buf_upd_1 += buf_len;
+ }
+ break;
+ }
+ len = len - 4;
+ temp_buf_main += (buf_len + 4);
+ processed += buf_len;
+ }
+ if (fwd_info->type == TYPE_DATA && len_upd_1) {
+ if (flag_buf_1)
+ temp_ptr_upd = fwd_info->buf_upd_1_a;
+ else
+ temp_ptr_upd = fwd_info->buf_upd_1_b;
+ temp_ptr_upd->ctxt &= 0x00FFFFFF;
+ temp_ptr_upd->ctxt |=
+ (SET_PD_CTXT(ctxt_upd_1));
+ atomic_set(&temp_ptr_upd->in_busy, 1);
+ diagfwd_data_process_done(fwd_info,
+ temp_ptr_upd, len_upd_1);
+ }
+ if (len_cpd) {
+ if (flag_buf_1) {
+ driver->cpd_len_1 = len_cpd;
+ temp_ptr_cpd = fwd_info->buf_1;
+ } else {
+ driver->cpd_len_2 = len_cpd;
+ temp_ptr_cpd = fwd_info->buf_2;
+ }
+ temp_ptr_cpd->ctxt &= 0x00FFFFFF;
+ temp_ptr_cpd->ctxt |=
+ (SET_PD_CTXT(ctxt_cpd));
+ diagfwd_data_process_done(fwd_info,
+ temp_ptr_cpd, len_cpd);
+ } else {
+ if (flag_buf_1)
+ driver->cpd_len_1 = 0;
+ if (flag_buf_2)
+ driver->cpd_len_2 = 0;
+ }
+ mutex_unlock(&driver->diagfwd_untag_mutex);
+ } else {
+ diagfwd_data_read_done(fwd_info, buf, len);
+ }
+}
+
static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
unsigned char *buf, int len)
{
@@ -223,6 +440,7 @@ static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
struct diagfwd_buf_t *temp_buf = NULL;
struct diag_md_session_t *session_info = NULL;
uint8_t hdlc_disabled = 0;
+
if (!fwd_info || !buf || len <= 0) {
diag_ws_release();
return;
@@ -234,8 +452,8 @@ static void diagfwd_data_read_done(struct diagfwd_info *fwd_info,
break;
default:
pr_err_ratelimited("diag: In %s, invalid type %d for peripheral %d\n",
- __func__, fwd_info->type,
- fwd_info->peripheral);
+ __func__, fwd_info->type,
+ fwd_info->peripheral);
diag_ws_release();
return;
}
@@ -941,7 +1159,15 @@ void diagfwd_write_done(uint8_t peripheral, uint8_t type, int ctxt)
atomic_set(&fwd_info->buf_1->in_busy, 0);
else if (ctxt == 2 && fwd_info->buf_2)
atomic_set(&fwd_info->buf_2->in_busy, 0);
- else
+ else if (ctxt == 3 && fwd_info->buf_upd_1_a) {
+ atomic_set(&fwd_info->buf_upd_1_a->in_busy, 0);
+ if (driver->cpd_len_1 == 0)
+ atomic_set(&fwd_info->buf_1->in_busy, 0);
+ } else if (ctxt == 4 && fwd_info->buf_upd_1_b) {
+ atomic_set(&fwd_info->buf_upd_1_b->in_busy, 0);
+ if (driver->cpd_len_2 == 0)
+ atomic_set(&fwd_info->buf_2->in_busy, 0);
+ } else
pr_err("diag: In %s, invalid ctxt %d\n", __func__, ctxt);
diagfwd_queue_read(fwd_info);
@@ -1073,6 +1299,7 @@ static void diagfwd_queue_read(struct diagfwd_info *fwd_info)
void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
{
+ unsigned char *temp_buf;
if (!fwd_info)
return;
@@ -1125,6 +1352,54 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
fwd_info->type, 2);
}
+ if (driver->feature[fwd_info->peripheral].untag_header) {
+ if (!fwd_info->buf_upd_1_a) {
+ fwd_info->buf_upd_1_a =
+ kzalloc(sizeof(struct diagfwd_buf_t),
+ GFP_KERNEL);
+ if (!fwd_info->buf_upd_1_a)
+ goto err;
+ kmemleak_not_leak(fwd_info->buf_upd_1_a);
+ }
+
+ if (!fwd_info->buf_upd_1_a->data) {
+ fwd_info->buf_upd_1_a->data =
+ kzalloc(PERIPHERAL_BUF_SZ +
+ APF_DIAG_PADDING,
+ GFP_KERNEL);
+ if (!fwd_info->buf_upd_1_a->data)
+ goto err;
+ fwd_info->buf_upd_1_a->len = PERIPHERAL_BUF_SZ;
+ kmemleak_not_leak(fwd_info->buf_upd_1_a->data);
+ fwd_info->buf_upd_1_a->ctxt = SET_BUF_CTXT(
+ fwd_info->peripheral,
+ fwd_info->type, 3);
+ }
+ if (!fwd_info->buf_upd_1_b) {
+ fwd_info->buf_upd_1_b =
+ kzalloc(sizeof(struct diagfwd_buf_t),
+ GFP_KERNEL);
+ if (!fwd_info->buf_upd_1_b)
+ goto err;
+ kmemleak_not_leak(fwd_info->buf_upd_1_b);
+ }
+
+ if (!fwd_info->buf_upd_1_b->data) {
+ fwd_info->buf_upd_1_b->data =
+ kzalloc(PERIPHERAL_BUF_SZ +
+ APF_DIAG_PADDING,
+ GFP_KERNEL);
+ if (!fwd_info->buf_upd_1_b->data)
+ goto err;
+ fwd_info->buf_upd_1_b->len =
+ PERIPHERAL_BUF_SZ;
+ kmemleak_not_leak(fwd_info->buf_upd_1_b->data);
+ fwd_info->buf_upd_1_b->ctxt = SET_BUF_CTXT(
+ fwd_info->peripheral,
+ fwd_info->type, 4);
+ }
+ }
+
if (driver->supports_apps_hdlc_encoding) {
/* In support of hdlc encoding */
if (!fwd_info->buf_1->data_raw) {
@@ -1134,7 +1409,8 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
GFP_KERNEL);
if (!fwd_info->buf_1->data_raw)
goto err;
- fwd_info->buf_1->len_raw = PERIPHERAL_BUF_SZ;
+ fwd_info->buf_1->len_raw =
+ PERIPHERAL_BUF_SZ;
kmemleak_not_leak(fwd_info->buf_1->data_raw);
}
if (!fwd_info->buf_2->data_raw) {
@@ -1144,13 +1420,45 @@ void diagfwd_buffers_init(struct diagfwd_info *fwd_info)
GFP_KERNEL);
if (!fwd_info->buf_2->data_raw)
goto err;
- fwd_info->buf_2->len_raw = PERIPHERAL_BUF_SZ;
+ fwd_info->buf_2->len_raw =
+ PERIPHERAL_BUF_SZ;
kmemleak_not_leak(fwd_info->buf_2->data_raw);
}
+
+ if (driver->feature[fwd_info->peripheral].
+ untag_header) {
+ if (!fwd_info->buf_upd_1_a->data_raw) {
+ fwd_info->buf_upd_1_a->data_raw =
+ kzalloc(PERIPHERAL_BUF_SZ +
+ APF_DIAG_PADDING,
+ GFP_KERNEL);
+ if (!fwd_info->buf_upd_1_a->data_raw)
+ goto err;
+ fwd_info->buf_upd_1_a->len_raw =
+ PERIPHERAL_BUF_SZ;
+ temp_buf =
+ fwd_info->buf_upd_1_a->data_raw;
+ kmemleak_not_leak(temp_buf);
+ }
+ if (!fwd_info->buf_upd_1_b->data_raw) {
+ fwd_info->buf_upd_1_b->data_raw =
+ kzalloc(PERIPHERAL_BUF_SZ +
+ APF_DIAG_PADDING,
+ GFP_KERNEL);
+ if (!fwd_info->buf_upd_1_b->data_raw)
+ goto err;
+ fwd_info->buf_upd_1_b->len_raw =
+ PERIPHERAL_BUF_SZ;
+ temp_buf =
+ fwd_info->buf_upd_1_b->data_raw;
+ kmemleak_not_leak(temp_buf);
+ }
+ }
}
}
- if (fwd_info->type == TYPE_CMD && driver->supports_apps_hdlc_encoding) {
+ if (fwd_info->type == TYPE_CMD &&
+ driver->supports_apps_hdlc_encoding) {
/* In support of hdlc encoding */
if (!fwd_info->buf_1->data_raw) {
fwd_info->buf_1->data_raw = kzalloc(PERIPHERAL_BUF_SZ +
diff --git a/drivers/char/diag/diagfwd_peripheral.h b/drivers/char/diag/diagfwd_peripheral.h
index 23aa526b2c09..f483da81cc96 100644
--- a/drivers/char/diag/diagfwd_peripheral.h
+++ b/drivers/char/diag/diagfwd_peripheral.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -78,6 +78,8 @@ struct diagfwd_info {
void *ctxt;
struct diagfwd_buf_t *buf_1;
struct diagfwd_buf_t *buf_2;
+ struct diagfwd_buf_t *buf_upd_1_a;
+ struct diagfwd_buf_t *buf_upd_1_b;
struct diagfwd_buf_t *buf_ptr[NUM_WRITE_BUFFERS];
struct diag_peripheral_ops *p_ops;
struct diag_channel_ops *c_ops;
diff --git a/drivers/char/hw_random/msm-rng.c b/drivers/char/hw_random/msm-rng.c
index 96fb986402eb..296b23960815 100644
--- a/drivers/char/hw_random/msm-rng.c
+++ b/drivers/char/hw_random/msm-rng.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-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
@@ -156,6 +156,7 @@ static int msm_rng_probe(struct platform_device *pdev)
rng->hwrng.init = msm_rng_init,
rng->hwrng.cleanup = msm_rng_cleanup,
rng->hwrng.read = msm_rng_read,
+ rng->hwrng.quality = 700;
ret = devm_hwrng_register(&pdev->dev, &rng->hwrng);
if (ret) {
diff --git a/drivers/clk/msm/clock-gcc-8996.c b/drivers/clk/msm/clock-gcc-8996.c
index a9e0b53c3b22..e93e9c494023 100644
--- a/drivers/clk/msm/clock-gcc-8996.c
+++ b/drivers/clk/msm/clock-gcc-8996.c
@@ -105,6 +105,8 @@ DEFINE_CLK_DUMMY(gcc_ce1_axi_m_clk, 0);
DEFINE_CLK_DUMMY(measure_only_bimc_hmss_axi_clk, 0);
DEFINE_CLK_RPM_SMD_XO_BUFFER(ln_bb_clk, ln_bb_a_clk, LN_BB_CLK_ID);
+DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(ln_bb_clk_pin, ln_bb_a_clk_pin,
+ LN_BB_CLK_PIN_ID);
static DEFINE_CLK_VOTER(mcd_ce1_clk, &ce1_clk.c, 85710000);
static DEFINE_CLK_VOTER(pnoc_keepalive_a_clk, &pnoc_a_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(pnoc_msmbus_clk, &pnoc_clk.c, LONG_MAX);
@@ -1340,9 +1342,11 @@ static struct rcg_clk pdm2_clk_src = {
},
};
-/* Frequency table might change later */
static struct clk_freq_tbl ftbl_qspi_ser_clk_src[] = {
- F( 192000000, gpll4_out_main, 2, 0, 0),
+ F( 75000000, gpll0_out_main, 8, 0, 0),
+ F( 150000000, gpll0_out_main, 4, 0, 0),
+ F( 256000000, gpll4_out_main, 1.5, 0, 0),
+ F( 300000000, gpll0_out_main, 2, 0, 0),
F_END
};
@@ -3387,6 +3391,8 @@ static struct clk_lookup msm_clocks_rpm_8996[] = {
CLK_LIST(ipa_clk),
CLK_LIST(ln_bb_clk),
CLK_LIST(ln_bb_a_clk),
+ CLK_LIST(ln_bb_clk_pin),
+ CLK_LIST(ln_bb_a_clk_pin),
CLK_LIST(mcd_ce1_clk),
CLK_LIST(pnoc_keepalive_a_clk),
CLK_LIST(pnoc_msmbus_clk),
diff --git a/drivers/clk/msm/clock-gcc-8998.c b/drivers/clk/msm/clock-gcc-8998.c
index f9d713a22c76..b1c8cc43769f 100644
--- a/drivers/clk/msm/clock-gcc-8998.c
+++ b/drivers/clk/msm/clock-gcc-8998.c
@@ -42,6 +42,7 @@ static void __iomem *virt_dbgbase;
#define gpll0_out_main_source_val 1
#define gpll0_ao_source_val 1
#define gpll4_out_main_source_val 5
+#define gpll0_early_div_source_val 6
#define FIXDIV(div) (div ? (2 * (div) - 1) : (0))
@@ -164,6 +165,7 @@ static struct pll_vote_clk gpll0_ao = {
};
DEFINE_EXT_CLK(gpll0_out_main, &gpll0.c);
+DEFINE_EXT_CLK(gpll0_early_div, &gpll0.c);
static struct local_vote_clk gcc_mmss_gpll0_clk = {
.cbcr_reg = GCC_APCS_CLOCK_BRANCH_ENA_VOTE_1,
@@ -328,7 +330,7 @@ static struct clk_freq_tbl ftbl_blsp_qup_spi_apps_clk_src[] = {
F( 960000, cxo_clk_src, 10, 1, 2),
F( 4800000, cxo_clk_src, 4, 0, 0),
F( 9600000, cxo_clk_src, 2, 0, 0),
- F( 15000000, gpll0_out_main, 10, 1, 4),
+ F( 15000000, gpll0_early_div, 5, 1, 4),
F( 19200000, cxo_clk_src, 1, 0, 0),
F( 25000000, gpll0_out_main, 12, 1, 2),
F( 50000000, gpll0_out_main, 12, 0, 0),
@@ -496,10 +498,10 @@ static struct rcg_clk blsp1_qup6_spi_apps_clk_src = {
};
static struct clk_freq_tbl ftbl_blsp_uart_apps_clk_src[] = {
- F( 3686400, gpll0_out_main, 1, 96, 15625),
- F( 7372800, gpll0_out_main, 1, 192, 15625),
- F( 14745600, gpll0_out_main, 1, 384, 15625),
- F( 16000000, gpll0_out_main, 5, 2, 15),
+ F( 3686400, gpll0_early_div, 1, 192, 15625),
+ F( 7372800, gpll0_early_div, 1, 384, 15625),
+ F( 14745600, gpll0_early_div, 1, 768, 15625),
+ F( 16000000, gpll0_early_div, 1, 4, 75),
F( 19200000, cxo_clk_src, 1, 0, 0),
F( 24000000, gpll0_out_main, 5, 1, 5),
F( 32000000, gpll0_out_main, 1, 4, 75),
@@ -2732,6 +2734,8 @@ static int msm_gcc_8998_probe(struct platform_device *pdev)
if (ret)
return ret;
+ gpll0_early_div.c.rate = 300000000;
+
ret = enable_rpm_scaling();
if (ret < 0)
return ret;
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 64c4bf8f58a8..ce67145bb142 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -1123,6 +1123,8 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx,
struct cpumask nextcpu, *cpumask;
uint64_t us;
uint32_t pred_us;
+ uint64_t sec;
+ uint64_t nsec;
us = get_cluster_sleep_time(cluster, &nextcpu,
from_idle, &pred_us);
@@ -1134,11 +1136,20 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx,
goto failed_set_mode;
}
- us = (us + 1) * 1000;
clear_predict_history();
clear_cl_predict_history();
- do_div(us, NSEC_PER_SEC/SCLK_HZ);
+ us = us + 1;
+ sec = us;
+ do_div(sec, USEC_PER_SEC);
+ nsec = us - sec * USEC_PER_SEC;
+
+ sec = sec * SCLK_HZ;
+ if (nsec > 0) {
+ nsec = nsec * NSEC_PER_USEC;
+ do_div(nsec, NSEC_PER_SEC/SCLK_HZ);
+ }
+ us = sec + nsec;
msm_mpm_enter_sleep(us, from_idle, cpumask);
}
diff --git a/drivers/devfreq/governor_spdm_bw_hyp.c b/drivers/devfreq/governor_spdm_bw_hyp.c
index cd068a3097ce..f18b72af5fc4 100644
--- a/drivers/devfreq/governor_spdm_bw_hyp.c
+++ b/drivers/devfreq/governor_spdm_bw_hyp.c
@@ -1,5 +1,5 @@
/*
-*Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+*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
@@ -84,6 +84,10 @@ static irqreturn_t threaded_isr(int irq, void *dev_id)
(int)desc.arg[0], ext_status);
mutex_lock(&devfreqs_lock);
list_for_each_entry(data, &devfreqs, list) {
+ if (data == NULL || data->devfreq == NULL) {
+ pr_err("Spurious interrupts\n");
+ break;
+ }
if (data->spdm_client == desc.ret[0]) {
devfreq_monitor_suspend(data->devfreq);
mutex_lock(&data->devfreq->lock);
diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c
index dd184b50e5b4..284627806b88 100644
--- a/drivers/dma/ipu/ipu_irq.c
+++ b/drivers/dma/ipu/ipu_irq.c
@@ -272,7 +272,7 @@ static void ipu_irq_handler(struct irq_desc *desc)
u32 status;
int i, line;
- for (i = IPU_IRQ_NR_FN_BANKS; i < IPU_IRQ_NR_BANKS; i++) {
+ for (i = 0; i < IPU_IRQ_NR_BANKS; i++) {
struct ipu_irq_bank *bank = irq_bank + i;
raw_spin_lock(&bank_lock);
diff --git a/drivers/esoc/esoc-mdm-4x.c b/drivers/esoc/esoc-mdm-4x.c
index 7a5e89636b64..1e5f35d8422d 100644
--- a/drivers/esoc/esoc-mdm-4x.c
+++ b/drivers/esoc/esoc-mdm-4x.c
@@ -937,6 +937,10 @@ static int mdm9x55_setup_hw(struct mdm_ctrl *mdm,
mdm->dual_interface = of_property_read_bool(node,
"qcom,mdm-dual-link");
esoc->link_name = MDM9x55_PCIE;
+ ret = of_property_read_string(node, "qcom,mdm-link-info",
+ &esoc->link_info);
+ if (ret)
+ dev_info(mdm->dev, "esoc link info missing\n");
esoc->clink_ops = clink_ops;
esoc->parent = mdm->dev;
esoc->owner = THIS_MODULE;
diff --git a/drivers/esoc/esoc.h b/drivers/esoc/esoc.h
index efa2a1d5e5a6..755fb24bd60a 100644
--- a/drivers/esoc/esoc.h
+++ b/drivers/esoc/esoc.h
@@ -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
@@ -46,6 +46,7 @@ struct esoc_eng {
* struct esoc_clink: Representation of external esoc device
* @name: Name of the external esoc.
* @link_name: name of the physical link.
+ * @link_info: additional info about the physical link.
* @parent: parent device.
* @dev: device for userspace interface.
* @id: id of the external device.
@@ -62,6 +63,7 @@ struct esoc_eng {
struct esoc_clink {
const char *name;
const char *link_name;
+ const char *link_info;
struct device *parent;
struct device dev;
unsigned int id;
diff --git a/drivers/esoc/esoc_bus.c b/drivers/esoc/esoc_bus.c
index c4397f6fd196..f925607511ba 100644
--- a/drivers/esoc/esoc_bus.c
+++ b/drivers/esoc/esoc_bus.c
@@ -32,10 +32,19 @@ esoc_link_show(struct device *dev, struct device_attribute *attr,
to_esoc_clink(dev)->link_name);
}
+static ssize_t
+esoc_link_info_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, ESOC_LINK_LEN, "%s",
+ to_esoc_clink(dev)->link_info);
+}
+
static struct device_attribute esoc_clink_attrs[] = {
__ATTR_RO(esoc_name),
__ATTR_RO(esoc_link),
+ __ATTR_RO(esoc_link_info),
__ATTR_NULL,
};
diff --git a/drivers/esoc/esoc_client.c b/drivers/esoc/esoc_client.c
index e9932ea3e964..0fe7a83cc3c2 100644
--- a/drivers/esoc/esoc_client.c
+++ b/drivers/esoc/esoc_client.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -43,7 +43,7 @@ struct esoc_desc *devm_register_esoc_client(struct device *dev,
struct device_node *np = dev->of_node;
struct esoc_clink *esoc_clink;
struct esoc_desc *desc;
- char *esoc_name, *esoc_link;
+ char *esoc_name, *esoc_link, *esoc_link_info;
for (index = 0;; index++) {
esoc_prop = kasprintf(GFP_KERNEL, "esoc-%d", index);
@@ -85,16 +85,26 @@ struct esoc_desc *devm_register_esoc_client(struct device *dev,
kfree(esoc_name);
return ERR_PTR(-ENOMEM);
}
+ esoc_link_info = kasprintf(GFP_KERNEL, "%s",
+ esoc_clink->link_info);
+ if (IS_ERR_OR_NULL(esoc_link_info)) {
+ dev_err(dev, "unable to alloc link info name\n");
+ kfree(esoc_name);
+ kfree(esoc_link);
+ return ERR_PTR(-ENOMEM);
+ }
desc = devres_alloc(devm_esoc_desc_release,
sizeof(*desc), GFP_KERNEL);
if (IS_ERR_OR_NULL(desc)) {
kfree(esoc_name);
kfree(esoc_link);
+ kfree(esoc_link_info);
dev_err(dev, "unable to allocate esoc descriptor\n");
return ERR_PTR(-ENOMEM);
}
desc->name = esoc_name;
desc->link = esoc_link;
+ desc->link_info = esoc_link_info;
desc->priv = esoc_clink;
devres_add(dev, desc);
return desc;
diff --git a/drivers/esoc/esoc_dev.c b/drivers/esoc/esoc_dev.c
index 26b8d0fe512b..ffb2237da5fa 100644
--- a/drivers/esoc/esoc_dev.c
+++ b/drivers/esoc/esoc_dev.c
@@ -214,7 +214,7 @@ static long esoc_dev_ioctl(struct file *file, unsigned int cmd,
esoc_clink->name);
return -EIO;
}
- put_user(req, (unsigned long __user *)uarg);
+ put_user(req, (unsigned int __user *)uarg);
}
return err;
@@ -227,7 +227,7 @@ static long esoc_dev_ioctl(struct file *file, unsigned int cmd,
err = clink_ops->get_status(&status, esoc_clink);
if (err)
return err;
- put_user(status, (unsigned long __user *)uarg);
+ put_user(status, (unsigned int __user *)uarg);
break;
case ESOC_WAIT_FOR_CRASH:
err = wait_event_interruptible(esoc_udev->evt_wait,
@@ -241,7 +241,7 @@ static long esoc_dev_ioctl(struct file *file, unsigned int cmd,
esoc_clink->name);
return -EIO;
}
- put_user(evt, (unsigned long __user *)uarg);
+ put_user(evt, (unsigned int __user *)uarg);
}
return err;
break;
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
index c161eeda417b..267749a94c5a 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
@@ -3704,9 +3704,15 @@ static void dce_v11_0_encoder_add(struct amdgpu_device *adev,
default:
encoder->possible_crtcs = 0x3;
break;
+ case 3:
+ encoder->possible_crtcs = 0x7;
+ break;
case 4:
encoder->possible_crtcs = 0xf;
break;
+ case 5:
+ encoder->possible_crtcs = 0x1f;
+ break;
case 6:
encoder->possible_crtcs = 0x3f;
break;
diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c
index 810c51d92b99..30672a3df8a9 100644
--- a/drivers/gpu/drm/ast/ast_post.c
+++ b/drivers/gpu/drm/ast/ast_post.c
@@ -58,13 +58,9 @@ bool ast_is_vga_enabled(struct drm_device *dev)
/* TODO 1180 */
} else {
ch = ast_io_read8(ast, AST_IO_VGA_ENABLE_PORT);
- if (ch) {
- ast_open_key(ast);
- ch = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xff);
- return ch & 0x04;
- }
+ return !!(ch & 0x01);
}
- return 0;
+ return false;
}
static const u8 extreginfo[] = { 0x0f, 0x04, 0x1c, 0xff };
@@ -375,8 +371,8 @@ void ast_post_gpu(struct drm_device *dev)
pci_write_config_dword(ast->dev->pdev, 0x04, reg);
ast_enable_vga(dev);
- ast_enable_mmio(dev);
ast_open_key(ast);
+ ast_enable_mmio(dev);
ast_set_def_ext_reg(dev);
if (ast->chip == AST2300 || ast->chip == AST2400)
@@ -1630,12 +1626,44 @@ static void ast_init_dram_2300(struct drm_device *dev)
temp |= 0x73;
ast_write32(ast, 0x12008, temp);
+ param.dram_freq = 396;
param.dram_type = AST_DDR3;
+ temp = ast_mindwm(ast, 0x1e6e2070);
if (temp & 0x01000000)
param.dram_type = AST_DDR2;
- param.dram_chipid = ast->dram_type;
- param.dram_freq = ast->mclk;
- param.vram_size = ast->vram_size;
+ switch (temp & 0x18000000) {
+ case 0:
+ param.dram_chipid = AST_DRAM_512Mx16;
+ break;
+ default:
+ case 0x08000000:
+ param.dram_chipid = AST_DRAM_1Gx16;
+ break;
+ case 0x10000000:
+ param.dram_chipid = AST_DRAM_2Gx16;
+ break;
+ case 0x18000000:
+ param.dram_chipid = AST_DRAM_4Gx16;
+ break;
+ }
+ switch (temp & 0x0c) {
+ default:
+ case 0x00:
+ param.vram_size = AST_VIDMEM_SIZE_8M;
+ break;
+
+ case 0x04:
+ param.vram_size = AST_VIDMEM_SIZE_16M;
+ break;
+
+ case 0x08:
+ param.vram_size = AST_VIDMEM_SIZE_32M;
+ break;
+
+ case 0x0c:
+ param.vram_size = AST_VIDMEM_SIZE_64M;
+ break;
+ }
if (param.dram_type == AST_DDR3) {
get_ddr3_info(ast, &param);
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 1ac29d703c12..ea443fafb934 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -265,7 +265,7 @@ mode_fixup(struct drm_atomic_state *state)
struct drm_connector *connector;
struct drm_connector_state *conn_state;
int i;
- bool ret;
+ int ret;
for_each_crtc_in_state(state, crtc, crtc_state, i) {
if (!crtc_state->mode_changed &&
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 7cb2815e815e..a3b96d691ac9 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -1812,7 +1812,7 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
mgr->payloads[i].num_slots = req_payload.num_slots;
} else if (mgr->payloads[i].num_slots) {
mgr->payloads[i].num_slots = 0;
- drm_dp_destroy_payload_step1(mgr, port, port->vcpi.vcpi, &mgr->payloads[i]);
+ drm_dp_destroy_payload_step1(mgr, port, mgr->payloads[i].vcpi, &mgr->payloads[i]);
req_payload.payload_state = mgr->payloads[i].payload_state;
mgr->payloads[i].start_slot = 0;
}
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 8c9ac021608f..cc1e16fd7e76 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -144,6 +144,9 @@ static struct edid_quirk {
/* Panel in Samsung NP700G7A-S01PL notebook reports 6bpc */
{ "SEC", 0xd033, EDID_QUIRK_FORCE_8BPC },
+
+ /* Rotel RSX-1058 forwards sink's EDID but only does HDMI 1.1*/
+ { "ETR", 13896, EDID_QUIRK_FORCE_8BPC },
};
/*
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 3f802163f7d4..e7c18519274a 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -6803,7 +6803,18 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
static void vlv_init_display_clock_gating(struct drm_i915_private *dev_priv)
{
- I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE);
+ u32 val;
+
+ /*
+ * On driver load, a pipe may be active and driving a DSI display.
+ * Preserve DPOUNIT_CLOCK_GATE_DISABLE to avoid the pipe getting stuck
+ * (and never recovering) in this case. intel_dsi_post_disable() will
+ * clear it when we turn off the display.
+ */
+ val = I915_READ(DSPCLK_GATE_D);
+ val &= DPOUNIT_CLOCK_GATE_DISABLE;
+ val |= VRHUNIT_CLOCK_GATE_DISABLE;
+ I915_WRITE(DSPCLK_GATE_D, val);
/*
* Disable trickle feed and enable pnd deadline calculation
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 79ea5a9f90ea..ebf8be80a3d9 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -59,7 +59,8 @@ msm_drm-y += adreno/adreno_device.o \
adreno/a5xx_gpu.o \
adreno/a5xx_power.o \
adreno/a5xx_preempt.o \
- adreno/a5xx_snapshot.o
+ adreno/a5xx_snapshot.o \
+ adreno/a5xx_counters.o
endif
msm_drm-$(CONFIG_DRM_MSM_MDP4) += mdp/mdp4/mdp4_crtc.o \
diff --git a/drivers/gpu/drm/msm/adreno/a5xx.xml.h b/drivers/gpu/drm/msm/adreno/a5xx.xml.h
index 56dad2217289..b73f4efb1b9d 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx.xml.h
+++ b/drivers/gpu/drm/msm/adreno/a5xx.xml.h
@@ -8,17 +8,17 @@ http://github.com/freedreno/envytools/
git clone https://github.com/freedreno/envytools.git
The rules-ng-ng source files this header was generated from are:
-- /local3/projects/drm/envytools/rnndb//adreno.xml ( 431 bytes, from 2016-10-24 21:12:27)
-- /local3/projects/drm/envytools/rnndb//freedreno_copyright.xml ( 1572 bytes, from 2016-10-24 21:12:27)
-- /local3/projects/drm/envytools/rnndb//adreno/a2xx.xml ( 32901 bytes, from 2016-10-24 21:12:27)
-- /local3/projects/drm/envytools/rnndb//adreno/adreno_common.xml ( 12025 bytes, from 2016-10-24 21:12:27)
-- /local3/projects/drm/envytools/rnndb//adreno/adreno_pm4.xml ( 19684 bytes, from 2016-10-24 21:12:27)
-- /local3/projects/drm/envytools/rnndb//adreno/a3xx.xml ( 83840 bytes, from 2016-10-24 21:12:27)
-- /local3/projects/drm/envytools/rnndb//adreno/a4xx.xml ( 110708 bytes, from 2016-10-24 21:12:27)
-- /local3/projects/drm/envytools/rnndb//adreno/a5xx.xml ( 81546 bytes, from 2016-10-31 16:38:41)
-- /local3/projects/drm/envytools/rnndb//adreno/ocmem.xml ( 1773 bytes, from 2016-10-24 21:12:27)
-
-Copyright (C) 2013-2016 by the following authors:
+- ./rnndb/adreno.xml ( 431 bytes, from 2016-10-24 21:12:27)
+- ./rnndb/freedreno_copyright.xml ( 1572 bytes, from 2016-10-24 21:12:27)
+- ./rnndb/adreno/a2xx.xml ( 32901 bytes, from 2016-10-24 21:12:27)
+- ./rnndb/adreno/adreno_common.xml ( 12025 bytes, from 2016-10-24 21:12:27)
+- ./rnndb/adreno/adreno_pm4.xml ( 19684 bytes, from 2016-10-24 21:12:27)
+- ./rnndb/adreno/a3xx.xml ( 83840 bytes, from 2016-10-24 21:12:27)
+- ./rnndb/adreno/a4xx.xml ( 110708 bytes, from 2016-10-24 21:12:27)
+- ./rnndb/adreno/a5xx.xml ( 86963 bytes, from 2017-03-03 16:01:09)
+- ./rnndb/adreno/ocmem.xml ( 1773 bytes, from 2016-10-24 21:12:27)
+
+Copyright (C) 2013-2017 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
- Ilia Mirkin <imirkin@alum.mit.edu> (imirkin)
@@ -1759,13 +1759,11 @@ static inline uint32_t A5XX_VBIF_TEST_BUS2_CTRL1_TEST_BUS2_DATA_SEL(uint32_t val
#define REG_A5XX_VBIF_TEST_BUS_OUT 0x0000308c
-#define REG_A5XX_VBIF_PERF_CNT_SEL0 0x000030d0
+static inline uint32_t REG_A5XX_VBIF_PERF_CNT_EN(uint32_t i0) { return 0x000030c0 + 0x1*i0; }
-#define REG_A5XX_VBIF_PERF_CNT_SEL1 0x000030d1
+static inline uint32_t REG_A5XX_VBIF_PERF_CNT_CLR(uint32_t i0) { return 0x000030c8 + 0x1*i0; }
-#define REG_A5XX_VBIF_PERF_CNT_SEL2 0x000030d2
-
-#define REG_A5XX_VBIF_PERF_CNT_SEL3 0x000030d3
+static inline uint32_t REG_A5XX_VBIF_PERF_CNT_SEL(uint32_t i0) { return 0x000030d0 + 0x1*i0; }
#define REG_A5XX_VBIF_PERF_CNT_LOW0 0x000030d8
@@ -1783,11 +1781,9 @@ static inline uint32_t A5XX_VBIF_TEST_BUS2_CTRL1_TEST_BUS2_DATA_SEL(uint32_t val
#define REG_A5XX_VBIF_PERF_CNT_HIGH3 0x000030e3
-#define REG_A5XX_VBIF_PERF_PWR_CNT_EN0 0x00003100
-
-#define REG_A5XX_VBIF_PERF_PWR_CNT_EN1 0x00003101
+static inline uint32_t REG_A5XX_VBIF_PERF_PWR_CNT_EN(uint32_t i0) { return 0x00003100 + 0x1*i0; }
-#define REG_A5XX_VBIF_PERF_PWR_CNT_EN2 0x00003102
+static inline uint32_t REG_A5XX_VBIF_PERF_PWR_CNT_CLR(uint32_t i0) { return 0x00003108 + 0x1*i0; }
#define REG_A5XX_VBIF_PERF_PWR_CNT_LOW0 0x00003110
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_counters.c b/drivers/gpu/drm/msm/adreno/a5xx_counters.c
new file mode 100644
index 000000000000..f1fac5535359
--- /dev/null
+++ b/drivers/gpu/drm/msm/adreno/a5xx_counters.c
@@ -0,0 +1,689 @@
+/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "a5xx_gpu.h"
+
+/*
+ * Fixed counters are not selectable, they always count the same thing.
+ * The countable is an index into the group: countable 0 = register 0,
+ * etc and they have no select register
+ */
+static int a5xx_counter_get_fixed(struct msm_gpu *gpu,
+ struct adreno_counter_group *group,
+ u32 countable, u32 *lo, u32 *hi)
+{
+ if (countable >= group->nr_counters)
+ return -EINVAL;
+
+ if (lo)
+ *lo = group->counters[countable].lo;
+ if (hi)
+ *hi = group->counters[countable].hi;
+
+ return countable;
+}
+
+/*
+ * Most counters are selectable in that they can be programmed to count
+ * different events; in most cases there are many more countables than
+ * counters. When a new counter is requested, first walk the list to see if any
+ * other counters in that group are counting the same countable and if so reuse
+ * that counter. If not find the first empty counter in the list and register
+ * that for the desired countable. If we are out of counters too bad so sad.
+ */
+static int a5xx_counter_get(struct msm_gpu *gpu,
+ struct adreno_counter_group *group,
+ u32 countable, u32 *lo, u32 *hi)
+{
+ struct adreno_counter *counter;
+ int i, empty = -1;
+
+ spin_lock(&group->lock);
+
+ for (i = 0; i < group->nr_counters; i++) {
+ counter = &group->counters[i];
+
+ if (counter->refcount) {
+ if (counter->countable == countable) {
+ counter->refcount++;
+
+ if (lo)
+ *lo = counter->lo;
+ if (hi)
+ *hi = counter->hi;
+
+ spin_unlock(&group->lock);
+ return i;
+ }
+ } else
+ empty = (empty == -1) ? i : empty;
+ }
+
+ if (empty == -1) {
+ spin_unlock(&group->lock);
+ return -EBUSY;
+ }
+
+ counter = &group->counters[empty];
+
+ counter->refcount = 1;
+ counter->countable = countable;
+
+ if (lo)
+ *lo = counter->lo;
+ if (hi)
+ *hi = counter->hi;
+
+ spin_unlock(&group->lock);
+
+ if (group->funcs.enable)
+ group->funcs.enable(gpu, group, empty);
+
+ return empty;
+}
+
+/* The majority of the non-fixed counter selects can be programmed by the CPU */
+static void a5xx_counter_enable_cpu(struct msm_gpu *gpu,
+ struct adreno_counter_group *group, int counterid)
+{
+ struct adreno_counter *counter = &group->counters[counterid];
+
+ gpu_write(gpu, counter->sel, counter->countable);
+}
+
+static void a5xx_counter_enable_pm4(struct msm_gpu *gpu,
+ struct adreno_counter_group *group, int counterid)
+{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+ struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
+ struct msm_ringbuffer *ring = gpu->rb[MSM_GPU_MAX_RINGS - 1];
+ struct adreno_counter *counter = &group->counters[counterid];
+
+ mutex_lock(&gpu->dev->struct_mutex);
+
+ /* Turn off preemption for the duration of this command */
+ OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1);
+ OUT_RING(ring, 0x02);
+
+ /* Turn off protected mode to write to special registers */
+ OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1);
+ OUT_RING(ring, 0);
+
+ /* Set the save preemption record for the ring/command */
+ OUT_PKT4(ring, REG_A5XX_CP_CONTEXT_SWITCH_SAVE_ADDR_LO, 2);
+ OUT_RING(ring, lower_32_bits(a5xx_gpu->preempt_iova[ring->id]));
+ OUT_RING(ring, upper_32_bits(a5xx_gpu->preempt_iova[ring->id]));
+
+ /* Turn back on protected mode */
+ OUT_PKT7(ring, CP_SET_PROTECTED_MODE, 1);
+ OUT_RING(ring, 1);
+
+ /* Idle the GPU */
+ OUT_PKT7(ring, CP_WAIT_FOR_IDLE, 0);
+
+ /* Enable the counter */
+ OUT_PKT4(ring, counter->sel, 1);
+ OUT_RING(ring, counter->countable);
+
+ /* Re-enable preemption */
+ OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1);
+ OUT_RING(ring, 0x00);
+
+ OUT_PKT7(ring, CP_PREEMPT_ENABLE_LOCAL, 1);
+ OUT_RING(ring, 0x01);
+
+ OUT_PKT7(ring, CP_YIELD_ENABLE, 1);
+ OUT_RING(ring, 0x01);
+
+ /* Yield */
+ OUT_PKT7(ring, CP_CONTEXT_SWITCH_YIELD, 4);
+ OUT_RING(ring, 0x00);
+ OUT_RING(ring, 0x00);
+ OUT_RING(ring, 0x01);
+ OUT_RING(ring, 0x01);
+
+ gpu->funcs->flush(gpu, ring);
+
+ /* Preempt into our ring if we need to */
+ a5xx_preempt_trigger(gpu);
+
+ /* wait for the operation to complete */
+ a5xx_idle(gpu, ring);
+
+ mutex_unlock(&gpu->dev->struct_mutex);
+}
+
+/*
+ * GPMU counters are selectable but the selects are muxed together in two
+ * registers
+ */
+static void a5xx_counter_enable_gpmu(struct msm_gpu *gpu,
+ struct adreno_counter_group *group, int counterid)
+{
+ struct adreno_counter *counter = &group->counters[counterid];
+ u32 reg;
+ int shift;
+
+ /*
+ * The selects for the GPMU counters are grouped together in two
+ * registers, a nibble for each counter. Counters 0-3 are located in
+ * GPMU_POWER_COUNTER_SELECT0 and 4-5 are in GPMU_POWER_COUNTER_SELECT1
+ */
+ if (counterid <= 3) {
+ shift = counterid << 3;
+ reg = REG_A5XX_GPMU_POWER_COUNTER_SELECT_0;
+ } else {
+ shift = (counterid - 4) << 3;
+ reg = REG_A5XX_GPMU_POWER_COUNTER_SELECT_1;
+ }
+
+ gpu_rmw(gpu, reg, 0xFF << shift, (counter->countable & 0xff) << shift);
+}
+
+/* VBIF counters are selectable but have their own programming process */
+static void a5xx_counter_enable_vbif(struct msm_gpu *gpu,
+ struct adreno_counter_group *group, int counterid)
+{
+ struct adreno_counter *counter = &group->counters[counterid];
+
+ gpu_write(gpu, REG_A5XX_VBIF_PERF_CNT_CLR(counterid), 1);
+ gpu_write(gpu, REG_A5XX_VBIF_PERF_CNT_CLR(counterid), 0);
+ gpu_write(gpu, REG_A5XX_VBIF_PERF_CNT_SEL(counterid),
+ counter->countable);
+ gpu_write(gpu, REG_A5XX_VBIF_PERF_CNT_EN(counterid), 1);
+}
+
+/*
+ * VBIF power counters are not slectable but need to be cleared/enabled before
+ * use
+ */
+static void a5xx_counter_enable_vbif_power(struct msm_gpu *gpu,
+ struct adreno_counter_group *group, int counterid)
+{
+ gpu_write(gpu, REG_A5XX_VBIF_PERF_PWR_CNT_CLR(counterid), 1);
+ gpu_write(gpu, REG_A5XX_VBIF_PERF_PWR_CNT_CLR(counterid), 0);
+ gpu_write(gpu, REG_A5XX_VBIF_PERF_PWR_CNT_EN(counterid), 1);
+}
+
+/* GPMU always on counter needs to be enabled before use */
+static void a5xx_counter_enable_alwayson_power(struct msm_gpu *gpu,
+ struct adreno_counter_group *group, int counterid)
+{
+ gpu_write(gpu, REG_A5XX_GPMU_ALWAYS_ON_COUNTER_RESET, 1);
+}
+
+static u64 a5xx_counter_read(struct msm_gpu *gpu,
+ struct adreno_counter_group *group, int counterid)
+{
+ if (counterid >= group->nr_counters)
+ return 0;
+
+ return gpu_read64(gpu, group->counters[counterid].lo,
+ group->counters[counterid].hi);
+}
+
+/*
+ * Selectable counters that are no longer used reset the countable to 0 to mark
+ * the counter as free
+ */
+static void a5xx_counter_put(struct msm_gpu *gpu,
+ struct adreno_counter_group *group, int counterid)
+{
+ struct adreno_counter *counter;
+
+ if (counterid >= group->nr_counters)
+ return;
+
+ counter = &group->counters[counterid];
+
+ spin_lock(&group->lock);
+ if (counter->refcount > 0)
+ counter->refcount--;
+ spin_unlock(&group->lock);
+}
+
+static struct adreno_counter a5xx_counters_alwayson[1] = {
+ { REG_A5XX_RBBM_ALWAYSON_COUNTER_LO,
+ REG_A5XX_RBBM_ALWAYSON_COUNTER_HI },
+};
+
+static struct adreno_counter a5xx_counters_ccu[] = {
+ { REG_A5XX_RBBM_PERFCTR_CCU_0_LO, REG_A5XX_RBBM_PERFCTR_CCU_0_HI,
+ REG_A5XX_RB_PERFCTR_CCU_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_CCU_1_LO, REG_A5XX_RBBM_PERFCTR_CCU_1_HI,
+ REG_A5XX_RB_PERFCTR_CCU_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_CCU_2_LO, REG_A5XX_RBBM_PERFCTR_CCU_2_HI,
+ REG_A5XX_RB_PERFCTR_CCU_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_CCU_3_LO, REG_A5XX_RBBM_PERFCTR_CCU_3_HI,
+ REG_A5XX_RB_PERFCTR_CCU_SEL_3 },
+};
+
+static struct adreno_counter a5xx_counters_cmp[] = {
+ { REG_A5XX_RBBM_PERFCTR_CMP_0_LO, REG_A5XX_RBBM_PERFCTR_CMP_0_HI,
+ REG_A5XX_RB_PERFCTR_CMP_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_CMP_1_LO, REG_A5XX_RBBM_PERFCTR_CMP_1_HI,
+ REG_A5XX_RB_PERFCTR_CMP_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_CMP_2_LO, REG_A5XX_RBBM_PERFCTR_CMP_2_HI,
+ REG_A5XX_RB_PERFCTR_CMP_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_CMP_3_LO, REG_A5XX_RBBM_PERFCTR_CMP_3_HI,
+ REG_A5XX_RB_PERFCTR_CMP_SEL_3 },
+};
+
+static struct adreno_counter a5xx_counters_cp[] = {
+ { REG_A5XX_RBBM_PERFCTR_CP_0_LO, REG_A5XX_RBBM_PERFCTR_CP_0_HI,
+ REG_A5XX_CP_PERFCTR_CP_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_CP_1_LO, REG_A5XX_RBBM_PERFCTR_CP_1_HI,
+ REG_A5XX_CP_PERFCTR_CP_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_CP_2_LO, REG_A5XX_RBBM_PERFCTR_CP_2_HI,
+ REG_A5XX_CP_PERFCTR_CP_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_CP_3_LO, REG_A5XX_RBBM_PERFCTR_CP_3_HI,
+ REG_A5XX_CP_PERFCTR_CP_SEL_3 },
+ { REG_A5XX_RBBM_PERFCTR_CP_4_LO, REG_A5XX_RBBM_PERFCTR_CP_4_HI,
+ REG_A5XX_CP_PERFCTR_CP_SEL_4 },
+ { REG_A5XX_RBBM_PERFCTR_CP_5_LO, REG_A5XX_RBBM_PERFCTR_CP_5_HI,
+ REG_A5XX_CP_PERFCTR_CP_SEL_5 },
+ { REG_A5XX_RBBM_PERFCTR_CP_6_LO, REG_A5XX_RBBM_PERFCTR_CP_6_HI,
+ REG_A5XX_CP_PERFCTR_CP_SEL_6 },
+ { REG_A5XX_RBBM_PERFCTR_CP_7_LO, REG_A5XX_RBBM_PERFCTR_CP_7_HI,
+ REG_A5XX_CP_PERFCTR_CP_SEL_7 },
+};
+
+static struct adreno_counter a5xx_counters_hlsq[] = {
+ { REG_A5XX_RBBM_PERFCTR_HLSQ_0_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_0_HI,
+ REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_HLSQ_1_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_1_HI,
+ REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_HLSQ_2_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_2_HI,
+ REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_HLSQ_3_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_3_HI,
+ REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_3 },
+ { REG_A5XX_RBBM_PERFCTR_HLSQ_4_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_4_HI,
+ REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_4 },
+ { REG_A5XX_RBBM_PERFCTR_HLSQ_5_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_5_HI,
+ REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_5 },
+ { REG_A5XX_RBBM_PERFCTR_HLSQ_6_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_6_HI,
+ REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_6 },
+ { REG_A5XX_RBBM_PERFCTR_HLSQ_7_LO, REG_A5XX_RBBM_PERFCTR_HLSQ_7_HI,
+ REG_A5XX_HLSQ_PERFCTR_HLSQ_SEL_7 },
+};
+
+static struct adreno_counter a5xx_counters_lrz[] = {
+ { REG_A5XX_RBBM_PERFCTR_LRZ_0_LO, REG_A5XX_RBBM_PERFCTR_LRZ_0_HI,
+ REG_A5XX_GRAS_PERFCTR_LRZ_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_LRZ_1_LO, REG_A5XX_RBBM_PERFCTR_LRZ_1_HI,
+ REG_A5XX_GRAS_PERFCTR_LRZ_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_LRZ_2_LO, REG_A5XX_RBBM_PERFCTR_LRZ_2_HI,
+ REG_A5XX_GRAS_PERFCTR_LRZ_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_LRZ_3_LO, REG_A5XX_RBBM_PERFCTR_LRZ_3_HI,
+ REG_A5XX_GRAS_PERFCTR_LRZ_SEL_3 },
+};
+
+static struct adreno_counter a5xx_counters_pc[] = {
+ { REG_A5XX_RBBM_PERFCTR_PC_0_LO, REG_A5XX_RBBM_PERFCTR_PC_0_HI,
+ REG_A5XX_PC_PERFCTR_PC_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_PC_1_LO, REG_A5XX_RBBM_PERFCTR_PC_1_HI,
+ REG_A5XX_PC_PERFCTR_PC_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_PC_2_LO, REG_A5XX_RBBM_PERFCTR_PC_2_HI,
+ REG_A5XX_PC_PERFCTR_PC_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_PC_3_LO, REG_A5XX_RBBM_PERFCTR_PC_3_HI,
+ REG_A5XX_PC_PERFCTR_PC_SEL_3 },
+ { REG_A5XX_RBBM_PERFCTR_PC_4_LO, REG_A5XX_RBBM_PERFCTR_PC_4_HI,
+ REG_A5XX_PC_PERFCTR_PC_SEL_4 },
+ { REG_A5XX_RBBM_PERFCTR_PC_5_LO, REG_A5XX_RBBM_PERFCTR_PC_5_HI,
+ REG_A5XX_PC_PERFCTR_PC_SEL_5 },
+ { REG_A5XX_RBBM_PERFCTR_PC_6_LO, REG_A5XX_RBBM_PERFCTR_PC_6_HI,
+ REG_A5XX_PC_PERFCTR_PC_SEL_6 },
+ { REG_A5XX_RBBM_PERFCTR_PC_7_LO, REG_A5XX_RBBM_PERFCTR_PC_7_HI,
+ REG_A5XX_PC_PERFCTR_PC_SEL_7 },
+};
+
+static struct adreno_counter a5xx_counters_ras[] = {
+ { REG_A5XX_RBBM_PERFCTR_RAS_0_LO, REG_A5XX_RBBM_PERFCTR_RAS_0_HI,
+ REG_A5XX_GRAS_PERFCTR_RAS_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_RAS_1_LO, REG_A5XX_RBBM_PERFCTR_RAS_1_HI,
+ REG_A5XX_GRAS_PERFCTR_RAS_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_RAS_2_LO, REG_A5XX_RBBM_PERFCTR_RAS_2_HI,
+ REG_A5XX_GRAS_PERFCTR_RAS_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_RAS_3_LO, REG_A5XX_RBBM_PERFCTR_RAS_3_HI,
+ REG_A5XX_GRAS_PERFCTR_RAS_SEL_3 },
+};
+
+static struct adreno_counter a5xx_counters_rb[] = {
+ { REG_A5XX_RBBM_PERFCTR_RB_0_LO, REG_A5XX_RBBM_PERFCTR_RB_0_HI,
+ REG_A5XX_RB_PERFCTR_RB_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_RB_1_LO, REG_A5XX_RBBM_PERFCTR_RB_1_HI,
+ REG_A5XX_RB_PERFCTR_RB_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_RB_2_LO, REG_A5XX_RBBM_PERFCTR_RB_2_HI,
+ REG_A5XX_RB_PERFCTR_RB_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_RB_3_LO, REG_A5XX_RBBM_PERFCTR_RB_3_HI,
+ REG_A5XX_RB_PERFCTR_RB_SEL_3 },
+ { REG_A5XX_RBBM_PERFCTR_RB_4_LO, REG_A5XX_RBBM_PERFCTR_RB_4_HI,
+ REG_A5XX_RB_PERFCTR_RB_SEL_4 },
+ { REG_A5XX_RBBM_PERFCTR_RB_5_LO, REG_A5XX_RBBM_PERFCTR_RB_5_HI,
+ REG_A5XX_RB_PERFCTR_RB_SEL_5 },
+ { REG_A5XX_RBBM_PERFCTR_RB_6_LO, REG_A5XX_RBBM_PERFCTR_RB_6_HI,
+ REG_A5XX_RB_PERFCTR_RB_SEL_6 },
+ { REG_A5XX_RBBM_PERFCTR_RB_7_LO, REG_A5XX_RBBM_PERFCTR_RB_7_HI,
+ REG_A5XX_RB_PERFCTR_RB_SEL_7 },
+};
+
+static struct adreno_counter a5xx_counters_rbbm[] = {
+ { REG_A5XX_RBBM_PERFCTR_RBBM_0_LO, REG_A5XX_RBBM_PERFCTR_RBBM_0_HI,
+ REG_A5XX_RBBM_PERFCTR_RBBM_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_RBBM_1_LO, REG_A5XX_RBBM_PERFCTR_RBBM_1_HI,
+ REG_A5XX_RBBM_PERFCTR_RBBM_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_RBBM_2_LO, REG_A5XX_RBBM_PERFCTR_RBBM_2_HI,
+ REG_A5XX_RBBM_PERFCTR_RBBM_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_RBBM_3_LO, REG_A5XX_RBBM_PERFCTR_RBBM_3_HI,
+ REG_A5XX_RBBM_PERFCTR_RBBM_SEL_3 },
+};
+
+static struct adreno_counter a5xx_counters_sp[] = {
+ { REG_A5XX_RBBM_PERFCTR_SP_0_LO, REG_A5XX_RBBM_PERFCTR_SP_0_HI,
+ REG_A5XX_SP_PERFCTR_SP_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_SP_1_LO, REG_A5XX_RBBM_PERFCTR_SP_1_HI,
+ REG_A5XX_SP_PERFCTR_SP_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_SP_2_LO, REG_A5XX_RBBM_PERFCTR_SP_2_HI,
+ REG_A5XX_SP_PERFCTR_SP_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_SP_3_LO, REG_A5XX_RBBM_PERFCTR_SP_3_HI,
+ REG_A5XX_SP_PERFCTR_SP_SEL_3 },
+ { REG_A5XX_RBBM_PERFCTR_SP_4_LO, REG_A5XX_RBBM_PERFCTR_SP_4_HI,
+ REG_A5XX_SP_PERFCTR_SP_SEL_4 },
+ { REG_A5XX_RBBM_PERFCTR_SP_5_LO, REG_A5XX_RBBM_PERFCTR_SP_5_HI,
+ REG_A5XX_SP_PERFCTR_SP_SEL_5 },
+ { REG_A5XX_RBBM_PERFCTR_SP_6_LO, REG_A5XX_RBBM_PERFCTR_SP_6_HI,
+ REG_A5XX_SP_PERFCTR_SP_SEL_6 },
+ { REG_A5XX_RBBM_PERFCTR_SP_7_LO, REG_A5XX_RBBM_PERFCTR_SP_7_HI,
+ REG_A5XX_SP_PERFCTR_SP_SEL_7 },
+ { REG_A5XX_RBBM_PERFCTR_SP_8_LO, REG_A5XX_RBBM_PERFCTR_SP_8_HI,
+ REG_A5XX_SP_PERFCTR_SP_SEL_8 },
+ { REG_A5XX_RBBM_PERFCTR_SP_9_LO, REG_A5XX_RBBM_PERFCTR_SP_9_HI,
+ REG_A5XX_SP_PERFCTR_SP_SEL_9 },
+ { REG_A5XX_RBBM_PERFCTR_SP_10_LO, REG_A5XX_RBBM_PERFCTR_SP_10_HI,
+ REG_A5XX_SP_PERFCTR_SP_SEL_10 },
+ { REG_A5XX_RBBM_PERFCTR_SP_11_LO, REG_A5XX_RBBM_PERFCTR_SP_11_HI,
+ REG_A5XX_SP_PERFCTR_SP_SEL_11 },
+};
+
+static struct adreno_counter a5xx_counters_tp[] = {
+ { REG_A5XX_RBBM_PERFCTR_TP_0_LO, REG_A5XX_RBBM_PERFCTR_TP_0_HI,
+ REG_A5XX_TPL1_PERFCTR_TP_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_TP_1_LO, REG_A5XX_RBBM_PERFCTR_TP_1_HI,
+ REG_A5XX_TPL1_PERFCTR_TP_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_TP_2_LO, REG_A5XX_RBBM_PERFCTR_TP_2_HI,
+ REG_A5XX_TPL1_PERFCTR_TP_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_TP_3_LO, REG_A5XX_RBBM_PERFCTR_TP_3_HI,
+ REG_A5XX_TPL1_PERFCTR_TP_SEL_3 },
+ { REG_A5XX_RBBM_PERFCTR_TP_4_LO, REG_A5XX_RBBM_PERFCTR_TP_4_HI,
+ REG_A5XX_TPL1_PERFCTR_TP_SEL_4 },
+ { REG_A5XX_RBBM_PERFCTR_TP_5_LO, REG_A5XX_RBBM_PERFCTR_TP_5_HI,
+ REG_A5XX_TPL1_PERFCTR_TP_SEL_5 },
+ { REG_A5XX_RBBM_PERFCTR_TP_6_LO, REG_A5XX_RBBM_PERFCTR_TP_6_HI,
+ REG_A5XX_TPL1_PERFCTR_TP_SEL_6 },
+ { REG_A5XX_RBBM_PERFCTR_TP_7_LO, REG_A5XX_RBBM_PERFCTR_TP_7_HI,
+ REG_A5XX_TPL1_PERFCTR_TP_SEL_7 },
+};
+
+static struct adreno_counter a5xx_counters_tse[] = {
+ { REG_A5XX_RBBM_PERFCTR_TSE_0_LO, REG_A5XX_RBBM_PERFCTR_TSE_0_HI,
+ REG_A5XX_GRAS_PERFCTR_TSE_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_TSE_1_LO, REG_A5XX_RBBM_PERFCTR_TSE_1_HI,
+ REG_A5XX_GRAS_PERFCTR_TSE_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_TSE_2_LO, REG_A5XX_RBBM_PERFCTR_TSE_2_HI,
+ REG_A5XX_GRAS_PERFCTR_TSE_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_TSE_3_LO, REG_A5XX_RBBM_PERFCTR_TSE_3_HI,
+ REG_A5XX_GRAS_PERFCTR_TSE_SEL_3 },
+};
+
+static struct adreno_counter a5xx_counters_uche[] = {
+ { REG_A5XX_RBBM_PERFCTR_UCHE_0_LO, REG_A5XX_RBBM_PERFCTR_UCHE_0_HI,
+ REG_A5XX_UCHE_PERFCTR_UCHE_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_UCHE_1_LO, REG_A5XX_RBBM_PERFCTR_UCHE_1_HI,
+ REG_A5XX_UCHE_PERFCTR_UCHE_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_UCHE_2_LO, REG_A5XX_RBBM_PERFCTR_UCHE_2_HI,
+ REG_A5XX_UCHE_PERFCTR_UCHE_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_UCHE_3_LO, REG_A5XX_RBBM_PERFCTR_UCHE_3_HI,
+ REG_A5XX_UCHE_PERFCTR_UCHE_SEL_3 },
+ { REG_A5XX_RBBM_PERFCTR_UCHE_4_LO, REG_A5XX_RBBM_PERFCTR_UCHE_4_HI,
+ REG_A5XX_UCHE_PERFCTR_UCHE_SEL_4 },
+ { REG_A5XX_RBBM_PERFCTR_UCHE_5_LO, REG_A5XX_RBBM_PERFCTR_UCHE_5_HI,
+ REG_A5XX_UCHE_PERFCTR_UCHE_SEL_5 },
+ { REG_A5XX_RBBM_PERFCTR_UCHE_6_LO, REG_A5XX_RBBM_PERFCTR_UCHE_6_HI,
+ REG_A5XX_UCHE_PERFCTR_UCHE_SEL_6 },
+ { REG_A5XX_RBBM_PERFCTR_UCHE_7_LO, REG_A5XX_RBBM_PERFCTR_UCHE_7_HI,
+ REG_A5XX_UCHE_PERFCTR_UCHE_SEL_7 },
+};
+
+static struct adreno_counter a5xx_counters_vfd[] = {
+ { REG_A5XX_RBBM_PERFCTR_VFD_0_LO, REG_A5XX_RBBM_PERFCTR_VFD_0_HI,
+ REG_A5XX_VFD_PERFCTR_VFD_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_VFD_1_LO, REG_A5XX_RBBM_PERFCTR_VFD_1_HI,
+ REG_A5XX_VFD_PERFCTR_VFD_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_VFD_2_LO, REG_A5XX_RBBM_PERFCTR_VFD_2_HI,
+ REG_A5XX_VFD_PERFCTR_VFD_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_VFD_3_LO, REG_A5XX_RBBM_PERFCTR_VFD_3_HI,
+ REG_A5XX_VFD_PERFCTR_VFD_SEL_3 },
+ { REG_A5XX_RBBM_PERFCTR_VFD_4_LO, REG_A5XX_RBBM_PERFCTR_VFD_4_HI,
+ REG_A5XX_VFD_PERFCTR_VFD_SEL_4 },
+ { REG_A5XX_RBBM_PERFCTR_VFD_5_LO, REG_A5XX_RBBM_PERFCTR_VFD_5_HI,
+ REG_A5XX_VFD_PERFCTR_VFD_SEL_5 },
+ { REG_A5XX_RBBM_PERFCTR_VFD_6_LO, REG_A5XX_RBBM_PERFCTR_VFD_6_HI,
+ REG_A5XX_VFD_PERFCTR_VFD_SEL_6 },
+ { REG_A5XX_RBBM_PERFCTR_VFD_7_LO, REG_A5XX_RBBM_PERFCTR_VFD_7_HI,
+ REG_A5XX_VFD_PERFCTR_VFD_SEL_7 },
+};
+
+static struct adreno_counter a5xx_counters_vpc[] = {
+ { REG_A5XX_RBBM_PERFCTR_VPC_0_LO, REG_A5XX_RBBM_PERFCTR_VPC_0_HI,
+ REG_A5XX_VPC_PERFCTR_VPC_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_VPC_1_LO, REG_A5XX_RBBM_PERFCTR_VPC_1_HI,
+ REG_A5XX_VPC_PERFCTR_VPC_SEL_1 },
+ { REG_A5XX_RBBM_PERFCTR_VPC_2_LO, REG_A5XX_RBBM_PERFCTR_VPC_2_HI,
+ REG_A5XX_VPC_PERFCTR_VPC_SEL_2 },
+ { REG_A5XX_RBBM_PERFCTR_VPC_3_LO, REG_A5XX_RBBM_PERFCTR_VPC_3_HI,
+ REG_A5XX_VPC_PERFCTR_VPC_SEL_3 },
+};
+
+static struct adreno_counter a5xx_counters_vsc[] = {
+ { REG_A5XX_RBBM_PERFCTR_VSC_0_LO, REG_A5XX_RBBM_PERFCTR_VSC_0_HI,
+ REG_A5XX_VSC_PERFCTR_VSC_SEL_0 },
+ { REG_A5XX_RBBM_PERFCTR_VSC_1_LO, REG_A5XX_RBBM_PERFCTR_VSC_1_HI,
+ REG_A5XX_VSC_PERFCTR_VSC_SEL_1 },
+};
+
+static struct adreno_counter a5xx_counters_power_ccu[] = {
+ { REG_A5XX_CCU_POWER_COUNTER_0_LO, REG_A5XX_CCU_POWER_COUNTER_0_HI,
+ REG_A5XX_RB_POWERCTR_CCU_SEL_0 },
+ { REG_A5XX_CCU_POWER_COUNTER_1_LO, REG_A5XX_CCU_POWER_COUNTER_1_HI,
+ REG_A5XX_RB_POWERCTR_CCU_SEL_1 },
+};
+
+static struct adreno_counter a5xx_counters_power_cp[] = {
+ { REG_A5XX_CP_POWER_COUNTER_0_LO, REG_A5XX_CP_POWER_COUNTER_0_HI,
+ REG_A5XX_CP_POWERCTR_CP_SEL_0 },
+ { REG_A5XX_CP_POWER_COUNTER_1_LO, REG_A5XX_CP_POWER_COUNTER_1_HI,
+ REG_A5XX_CP_POWERCTR_CP_SEL_1 },
+ { REG_A5XX_CP_POWER_COUNTER_2_LO, REG_A5XX_CP_POWER_COUNTER_2_HI,
+ REG_A5XX_CP_POWERCTR_CP_SEL_2 },
+ { REG_A5XX_CP_POWER_COUNTER_3_LO, REG_A5XX_CP_POWER_COUNTER_3_HI,
+ REG_A5XX_CP_POWERCTR_CP_SEL_3 },
+};
+
+static struct adreno_counter a5xx_counters_power_rb[] = {
+ { REG_A5XX_RB_POWER_COUNTER_0_LO, REG_A5XX_RB_POWER_COUNTER_0_HI,
+ REG_A5XX_RB_POWERCTR_RB_SEL_0 },
+ { REG_A5XX_RB_POWER_COUNTER_1_LO, REG_A5XX_RB_POWER_COUNTER_1_HI,
+ REG_A5XX_RB_POWERCTR_RB_SEL_1 },
+ { REG_A5XX_RB_POWER_COUNTER_2_LO, REG_A5XX_RB_POWER_COUNTER_2_HI,
+ REG_A5XX_RB_POWERCTR_RB_SEL_2 },
+ { REG_A5XX_RB_POWER_COUNTER_3_LO, REG_A5XX_RB_POWER_COUNTER_3_HI,
+ REG_A5XX_RB_POWERCTR_RB_SEL_3 },
+};
+
+static struct adreno_counter a5xx_counters_power_sp[] = {
+ { REG_A5XX_SP_POWER_COUNTER_0_LO, REG_A5XX_SP_POWER_COUNTER_0_HI,
+ REG_A5XX_SP_POWERCTR_SP_SEL_0 },
+ { REG_A5XX_SP_POWER_COUNTER_1_LO, REG_A5XX_SP_POWER_COUNTER_1_HI,
+ REG_A5XX_SP_POWERCTR_SP_SEL_1 },
+ { REG_A5XX_SP_POWER_COUNTER_2_LO, REG_A5XX_SP_POWER_COUNTER_2_HI,
+ REG_A5XX_SP_POWERCTR_SP_SEL_2 },
+ { REG_A5XX_SP_POWER_COUNTER_3_LO, REG_A5XX_SP_POWER_COUNTER_3_HI,
+ REG_A5XX_SP_POWERCTR_SP_SEL_3 },
+};
+
+static struct adreno_counter a5xx_counters_power_tp[] = {
+ { REG_A5XX_TP_POWER_COUNTER_0_LO, REG_A5XX_TP_POWER_COUNTER_0_HI,
+ REG_A5XX_TPL1_POWERCTR_TP_SEL_0 },
+ { REG_A5XX_TP_POWER_COUNTER_1_LO, REG_A5XX_TP_POWER_COUNTER_1_HI,
+ REG_A5XX_TPL1_POWERCTR_TP_SEL_1 },
+ { REG_A5XX_TP_POWER_COUNTER_2_LO, REG_A5XX_TP_POWER_COUNTER_2_HI,
+ REG_A5XX_TPL1_POWERCTR_TP_SEL_2 },
+ { REG_A5XX_TP_POWER_COUNTER_3_LO, REG_A5XX_TP_POWER_COUNTER_3_HI,
+ REG_A5XX_TPL1_POWERCTR_TP_SEL_3 },
+};
+
+static struct adreno_counter a5xx_counters_power_uche[] = {
+ { REG_A5XX_UCHE_POWER_COUNTER_0_LO, REG_A5XX_UCHE_POWER_COUNTER_0_HI,
+ REG_A5XX_UCHE_POWERCTR_UCHE_SEL_0 },
+ { REG_A5XX_UCHE_POWER_COUNTER_1_LO, REG_A5XX_UCHE_POWER_COUNTER_1_HI,
+ REG_A5XX_UCHE_POWERCTR_UCHE_SEL_1 },
+ { REG_A5XX_UCHE_POWER_COUNTER_2_LO, REG_A5XX_UCHE_POWER_COUNTER_2_HI,
+ REG_A5XX_UCHE_POWERCTR_UCHE_SEL_2 },
+ { REG_A5XX_UCHE_POWER_COUNTER_3_LO, REG_A5XX_UCHE_POWER_COUNTER_3_HI,
+ REG_A5XX_UCHE_POWERCTR_UCHE_SEL_3 },
+};
+
+static struct adreno_counter a5xx_counters_vbif[] = {
+ { REG_A5XX_VBIF_PERF_CNT_LOW0, REG_A5XX_VBIF_PERF_CNT_HIGH0 },
+ { REG_A5XX_VBIF_PERF_CNT_LOW1, REG_A5XX_VBIF_PERF_CNT_HIGH1 },
+ { REG_A5XX_VBIF_PERF_CNT_LOW2, REG_A5XX_VBIF_PERF_CNT_HIGH2 },
+ { REG_A5XX_VBIF_PERF_CNT_LOW3, REG_A5XX_VBIF_PERF_CNT_HIGH3 },
+};
+
+static struct adreno_counter a5xx_counters_gpmu[] = {
+ { REG_A5XX_GPMU_POWER_COUNTER_0_LO, REG_A5XX_GPMU_POWER_COUNTER_0_HI },
+ { REG_A5XX_GPMU_POWER_COUNTER_1_LO, REG_A5XX_GPMU_POWER_COUNTER_1_HI },
+ { REG_A5XX_GPMU_POWER_COUNTER_2_LO, REG_A5XX_GPMU_POWER_COUNTER_2_HI },
+ { REG_A5XX_GPMU_POWER_COUNTER_3_LO, REG_A5XX_GPMU_POWER_COUNTER_3_HI },
+ { REG_A5XX_GPMU_POWER_COUNTER_4_LO, REG_A5XX_GPMU_POWER_COUNTER_4_HI },
+ { REG_A5XX_GPMU_POWER_COUNTER_5_LO, REG_A5XX_GPMU_POWER_COUNTER_5_HI },
+};
+
+static struct adreno_counter a5xx_counters_vbif_power[] = {
+ { REG_A5XX_VBIF_PERF_PWR_CNT_LOW0, REG_A5XX_VBIF_PERF_PWR_CNT_HIGH0 },
+ { REG_A5XX_VBIF_PERF_PWR_CNT_LOW1, REG_A5XX_VBIF_PERF_PWR_CNT_HIGH1 },
+ { REG_A5XX_VBIF_PERF_PWR_CNT_LOW2, REG_A5XX_VBIF_PERF_PWR_CNT_HIGH2 },
+};
+
+static struct adreno_counter a5xx_counters_alwayson_power[] = {
+ { REG_A5XX_GPMU_ALWAYS_ON_COUNTER_LO,
+ REG_A5XX_GPMU_ALWAYS_ON_COUNTER_HI },
+};
+
+#define DEFINE_COUNTER_GROUP(_name, _array, _get, _enable, _put) \
+static struct adreno_counter_group _name = { \
+ .counters = _array, \
+ .nr_counters = ARRAY_SIZE(_array), \
+ .lock = __SPIN_LOCK_UNLOCKED(_name.lock), \
+ .funcs = { \
+ .get = _get, \
+ .enable = _enable, \
+ .read = a5xx_counter_read, \
+ .put = _put, \
+ }, \
+}
+
+#define DEFAULT_COUNTER_GROUP(_name, _array) DEFINE_COUNTER_GROUP(_name, \
+ _array, a5xx_counter_get, a5xx_counter_enable_cpu, a5xx_counter_put)
+
+#define SPTP_COUNTER_GROUP(_name, _array) DEFINE_COUNTER_GROUP(_name, \
+ _array, a5xx_counter_get, a5xx_counter_enable_pm4, a5xx_counter_put)
+
+/* "standard" counters */
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_cp, a5xx_counters_cp);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_rbbm, a5xx_counters_rbbm);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_pc, a5xx_counters_pc);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_vfd, a5xx_counters_vfd);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_vpc, a5xx_counters_vpc);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_ccu, a5xx_counters_ccu);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_cmp, a5xx_counters_cmp);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_tse, a5xx_counters_tse);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_ras, a5xx_counters_ras);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_uche, a5xx_counters_uche);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_rb, a5xx_counters_rb);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_vsc, a5xx_counters_vsc);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_lrz, a5xx_counters_lrz);
+
+/* SP/TP counters */
+SPTP_COUNTER_GROUP(a5xx_counter_group_hlsq, a5xx_counters_hlsq);
+SPTP_COUNTER_GROUP(a5xx_counter_group_tp, a5xx_counters_tp);
+SPTP_COUNTER_GROUP(a5xx_counter_group_sp, a5xx_counters_sp);
+
+/* Power counters */
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_power_ccu, a5xx_counters_power_ccu);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_power_cp, a5xx_counters_power_cp);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_power_rb, a5xx_counters_power_rb);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_power_sp, a5xx_counters_power_sp);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_power_tp, a5xx_counters_power_tp);
+DEFAULT_COUNTER_GROUP(a5xx_counter_group_power_uche, a5xx_counters_power_uche);
+
+DEFINE_COUNTER_GROUP(a5xx_counter_group_alwayson, a5xx_counters_alwayson,
+ a5xx_counter_get_fixed, NULL, NULL);
+DEFINE_COUNTER_GROUP(a5xx_counter_group_vbif, a5xx_counters_vbif,
+ a5xx_counter_get, a5xx_counter_enable_vbif, a5xx_counter_put);
+DEFINE_COUNTER_GROUP(a5xx_counter_group_gpmu, a5xx_counters_gpmu,
+ a5xx_counter_get, a5xx_counter_enable_gpmu, a5xx_counter_put);
+DEFINE_COUNTER_GROUP(a5xx_counter_group_vbif_power, a5xx_counters_vbif_power,
+ a5xx_counter_get_fixed, a5xx_counter_enable_vbif_power, NULL);
+DEFINE_COUNTER_GROUP(a5xx_counter_group_alwayson_power,
+ a5xx_counters_alwayson_power, a5xx_counter_get_fixed,
+ a5xx_counter_enable_alwayson_power, NULL);
+
+static const struct adreno_counter_group *a5xx_counter_groups[] = {
+ [MSM_COUNTER_GROUP_ALWAYSON] = &a5xx_counter_group_alwayson,
+ [MSM_COUNTER_GROUP_CCU] = &a5xx_counter_group_ccu,
+ [MSM_COUNTER_GROUP_CMP] = &a5xx_counter_group_cmp,
+ [MSM_COUNTER_GROUP_CP] = &a5xx_counter_group_cp,
+ [MSM_COUNTER_GROUP_HLSQ] = &a5xx_counter_group_hlsq,
+ [MSM_COUNTER_GROUP_LRZ] = &a5xx_counter_group_lrz,
+ [MSM_COUNTER_GROUP_PC] = &a5xx_counter_group_pc,
+ [MSM_COUNTER_GROUP_RAS] = &a5xx_counter_group_ras,
+ [MSM_COUNTER_GROUP_RB] = &a5xx_counter_group_rb,
+ [MSM_COUNTER_GROUP_RBBM] = &a5xx_counter_group_rbbm,
+ [MSM_COUNTER_GROUP_SP] = &a5xx_counter_group_sp,
+ [MSM_COUNTER_GROUP_TP] = &a5xx_counter_group_tp,
+ [MSM_COUNTER_GROUP_TSE] = &a5xx_counter_group_tse,
+ [MSM_COUNTER_GROUP_UCHE] = &a5xx_counter_group_uche,
+ [MSM_COUNTER_GROUP_VFD] = &a5xx_counter_group_vfd,
+ [MSM_COUNTER_GROUP_VPC] = &a5xx_counter_group_vpc,
+ [MSM_COUNTER_GROUP_VSC] = &a5xx_counter_group_vsc,
+ [MSM_COUNTER_GROUP_VBIF] = &a5xx_counter_group_vbif,
+ [MSM_COUNTER_GROUP_GPMU_PWR] = &a5xx_counter_group_gpmu,
+ [MSM_COUNTER_GROUP_CCU_PWR] = &a5xx_counter_group_power_ccu,
+ [MSM_COUNTER_GROUP_CP_PWR] = &a5xx_counter_group_power_cp,
+ [MSM_COUNTER_GROUP_RB_PWR] = &a5xx_counter_group_power_rb,
+ [MSM_COUNTER_GROUP_SP_PWR] = &a5xx_counter_group_power_sp,
+ [MSM_COUNTER_GROUP_TP_PWR] = &a5xx_counter_group_power_tp,
+ [MSM_COUNTER_GROUP_UCHE_PWR] = &a5xx_counter_group_power_uche,
+ [MSM_COUNTER_GROUP_VBIF_PWR] = &a5xx_counter_group_vbif_power,
+ [MSM_COUNTER_GROUP_ALWAYSON_PWR] =
+ &a5xx_counter_group_alwayson_power,
+};
+
+int a5xx_counters_init(struct adreno_gpu *adreno_gpu)
+{
+ adreno_gpu->counter_groups = a5xx_counter_groups;
+ adreno_gpu->nr_counter_groups = ARRAY_SIZE(a5xx_counter_groups);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
index f5847bc60c49..02c4f2e3155d 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -856,14 +856,6 @@ static inline bool _a5xx_check_idle(struct msm_gpu *gpu)
bool a5xx_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
{
- struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
- struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
-
- if (ring != a5xx_gpu->cur_ring) {
- WARN(1, "Tried to idle a non-current ringbuffer\n");
- return false;
- }
-
/* wait for CP to drain ringbuffer: */
if (!adreno_idle(gpu, ring))
return false;
@@ -1218,6 +1210,9 @@ static const struct adreno_gpu_funcs funcs = {
.show = a5xx_show,
#endif
.snapshot = a5xx_snapshot,
+ .get_counter = adreno_get_counter,
+ .read_counter = adreno_read_counter,
+ .put_counter = adreno_put_counter,
},
.get_timestamp = a5xx_get_timestamp,
};
@@ -1341,5 +1336,7 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev)
/* Set up the preemption specific bits and pieces for each ringbuffer */
a5xx_preempt_init(gpu);
+ a5xx_counters_init(adreno_gpu);
+
return gpu;
}
diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
index 3de14fe42a1b..8eb3838ffe90 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.h
@@ -184,4 +184,6 @@ static inline bool a5xx_in_preempt(struct a5xx_gpu *a5xx_gpu)
return !(atomic_read(&a5xx_gpu->preempt_state) == PREEMPT_NONE);
}
+int a5xx_counters_init(struct adreno_gpu *adreno_gpu);
+
#endif /* __A5XX_GPU_H__ */
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index f1883825354e..969ed810ce9d 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -709,3 +709,52 @@ void adreno_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot)
adreno_snapshot_os(gpu, snapshot);
adreno_snapshot_ringbuffers(gpu, snapshot);
}
+
+/* Return the group struct associated with the counter id */
+
+static struct adreno_counter_group *get_counter_group(struct msm_gpu *gpu,
+ u32 groupid)
+{
+ struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+
+ if (!adreno_gpu->counter_groups)
+ return ERR_PTR(-ENODEV);
+
+ if (groupid >= adreno_gpu->nr_counter_groups)
+ return ERR_PTR(-EINVAL);
+
+ return (struct adreno_counter_group *)
+ adreno_gpu->counter_groups[groupid];
+}
+
+int adreno_get_counter(struct msm_gpu *gpu, u32 groupid, u32 countable,
+ u32 *lo, u32 *hi)
+{
+ struct adreno_counter_group *group =
+ get_counter_group(gpu, groupid);
+
+ if (!IS_ERR_OR_NULL(group) && group->funcs.get)
+ return group->funcs.get(gpu, group, countable, lo, hi);
+
+ return -ENODEV;
+}
+
+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)
+ return group->funcs.read(gpu, group, counterid);
+
+ return 0;
+}
+
+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)
+ group->funcs.put(gpu, group, counterid);
+}
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 30461115281c..8e8f3e5182d6 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -99,6 +99,30 @@ struct adreno_rbmemptrs {
volatile unsigned int contextidr[MSM_GPU_MAX_RINGS];
};
+struct adreno_counter {
+ u32 lo;
+ u32 hi;
+ u32 sel;
+ u32 countable;
+ u32 refcount;
+};
+
+struct adreno_counter_group {
+ struct adreno_counter *counters;
+ size_t nr_counters;
+ spinlock_t lock;
+ struct {
+ int (*get)(struct msm_gpu *,
+ struct adreno_counter_group *, u32, u32 *, u32 *);
+ void (*enable)(struct msm_gpu *,
+ struct adreno_counter_group *, int);
+ u64 (*read)(struct msm_gpu *,
+ struct adreno_counter_group *, int);
+ void (*put)(struct msm_gpu *,
+ struct adreno_counter_group *, int);
+ } funcs;
+};
+
struct adreno_gpu {
struct msm_gpu base;
struct adreno_rev rev;
@@ -129,6 +153,9 @@ struct adreno_gpu {
uint32_t quirks;
uint32_t speed_bin;
+
+ const struct adreno_counter_group **counter_groups;
+ int nr_counter_groups;
};
#define to_adreno_gpu(x) container_of(x, struct adreno_gpu, base)
@@ -235,6 +262,11 @@ void adreno_gpu_cleanup(struct adreno_gpu *gpu);
void adreno_snapshot(struct msm_gpu *gpu, struct msm_snapshot *snapshot);
+int adreno_get_counter(struct msm_gpu *gpu, u32 groupid, u32 countable,
+ u32 *lo, u32 *hi);
+u64 adreno_read_counter(struct msm_gpu *gpu, u32 groupid, int counterid);
+void adreno_put_counter(struct msm_gpu *gpu, u32 groupid, int counterid);
+
/* ringbuffer helpers (the parts that are adreno specific) */
static inline void
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 532ff8677259..276329b7b10c 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -606,6 +606,8 @@ static int msm_open(struct drm_device *dev, struct drm_file *file)
if (IS_ERR(ctx))
return PTR_ERR(ctx);
+ INIT_LIST_HEAD(&ctx->counters);
+
file->driver_priv = ctx;
kms = priv->kms;
@@ -634,6 +636,9 @@ static void msm_postclose(struct drm_device *dev, struct drm_file *file)
if (kms && kms->funcs && kms->funcs->postclose)
kms->funcs->postclose(kms, file);
+ if (priv->gpu)
+ msm_gpu_cleanup_counters(priv->gpu, ctx);
+
mutex_lock(&dev->struct_mutex);
if (ctx && ctx->aspace && ctx->aspace != priv->gpu->aspace) {
ctx->aspace->mmu->funcs->detach(ctx->aspace->mmu);
@@ -1584,6 +1589,41 @@ void msm_send_crtc_notification(struct drm_crtc *crtc,
spin_unlock_irqrestore(&dev->event_lock, flags);
}
+static int msm_ioctl_counter_get(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct msm_file_private *ctx = file->driver_priv;
+ struct msm_drm_private *priv = dev->dev_private;
+
+ if (priv->gpu)
+ return msm_gpu_counter_get(priv->gpu, data, ctx);
+
+ return -ENODEV;
+}
+
+static int msm_ioctl_counter_put(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct msm_file_private *ctx = file->driver_priv;
+ struct msm_drm_private *priv = dev->dev_private;
+
+ if (priv->gpu)
+ return msm_gpu_counter_put(priv->gpu, data, ctx);
+
+ return -ENODEV;
+}
+
+static int msm_ioctl_counter_read(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+
+ if (priv->gpu)
+ return msm_gpu_counter_read(priv->gpu, data);
+
+ return -ENODEV;
+}
+
int msm_release(struct inode *inode, struct file *filp)
{
struct drm_file *file_priv = filp->private_data;
@@ -1619,6 +1659,12 @@ static const struct drm_ioctl_desc msm_ioctls[] = {
DRM_UNLOCKED|DRM_CONTROL_ALLOW),
DRM_IOCTL_DEF_DRV(MSM_DEREGISTER_EVENT, msm_ioctl_deregister_event,
DRM_UNLOCKED|DRM_CONTROL_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_COUNTER_GET, msm_ioctl_counter_get,
+ DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_COUNTER_PUT, msm_ioctl_counter_put,
+ DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_COUNTER_READ, msm_ioctl_counter_read,
+ DRM_AUTH|DRM_RENDER_ALLOW),
};
static const struct vm_operations_struct vm_ops = {
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index d8a4c34e9be0..d2d118cf7e07 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -76,6 +76,7 @@ struct msm_gem_vma;
struct msm_file_private {
struct msm_gem_address_space *aspace;
+ struct list_head counters;
};
enum msm_mdp_plane_property {
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 63128d11767e..d1455fbc980e 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -750,7 +750,10 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
size = PAGE_ALIGN(size);
+ mutex_lock(&dev->struct_mutex);
ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj);
+ mutex_unlock(&dev->struct_mutex);
+
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index 3176f301e7a8..5a505a8bf328 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -576,8 +576,7 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
if (submit->bos[i].flags & MSM_SUBMIT_BO_READ)
msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence);
-
- if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE)
+ else if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE)
msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence);
}
@@ -588,6 +587,118 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
return ret;
}
+struct msm_context_counter {
+ u32 groupid;
+ int counterid;
+ struct list_head node;
+};
+
+int msm_gpu_counter_get(struct msm_gpu *gpu, struct drm_msm_counter *data,
+ struct msm_file_private *ctx)
+{
+ struct msm_context_counter *entry;
+ int counterid;
+ u32 lo = 0, hi = 0;
+
+ if (!ctx || !gpu->funcs->get_counter)
+ return -ENODEV;
+
+ counterid = gpu->funcs->get_counter(gpu, data->groupid, data->countable,
+ &lo, &hi);
+
+ if (counterid < 0)
+ return counterid;
+
+ /*
+ * Check to see if the counter in question is already held by this
+ * process. If it does, put it back and return an error.
+ */
+ list_for_each_entry(entry, &ctx->counters, node) {
+ if (entry->groupid == data->groupid &&
+ entry->counterid == counterid) {
+ gpu->funcs->put_counter(gpu, data->groupid, counterid);
+ return -EBUSY;
+ }
+ }
+
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ gpu->funcs->put_counter(gpu, data->groupid, counterid);
+ return -ENOMEM;
+ }
+
+ entry->groupid = data->groupid;
+ entry->counterid = counterid;
+ list_add_tail(&entry->node, &ctx->counters);
+
+ data->counterid = counterid;
+ data->counter_lo = lo;
+ data->counter_hi = hi;
+
+ return 0;
+}
+
+int msm_gpu_counter_put(struct msm_gpu *gpu, struct drm_msm_counter *data,
+ struct msm_file_private *ctx)
+{
+ struct msm_context_counter *entry;
+
+ list_for_each_entry(entry, &ctx->counters, node) {
+ if (entry->groupid == data->groupid &&
+ entry->counterid == data->counterid) {
+ gpu->funcs->put_counter(gpu, data->groupid,
+ data->counterid);
+
+ list_del(&entry->node);
+ kfree(entry);
+
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+void msm_gpu_cleanup_counters(struct msm_gpu *gpu,
+ struct msm_file_private *ctx)
+{
+ struct msm_context_counter *entry, *tmp;
+
+ if (!ctx)
+ return;
+
+ list_for_each_entry_safe(entry, tmp, &ctx->counters, node) {
+ gpu->funcs->put_counter(gpu, entry->groupid, entry->counterid);
+ list_del(&entry->node);
+ kfree(entry);
+ }
+}
+
+u64 msm_gpu_counter_read(struct msm_gpu *gpu, struct drm_msm_counter_read *data)
+{
+ int i;
+
+ if (!gpu->funcs->read_counter)
+ return 0;
+
+ for (i = 0; i < data->nr_ops; i++) {
+ struct drm_msm_counter_read_op op;
+ void __user *ptr = (void __user *)(uintptr_t)
+ (data->ops + (i * sizeof(op)));
+
+ if (copy_from_user(&op, ptr, sizeof(op)))
+ return -EFAULT;
+
+ op.value = gpu->funcs->read_counter(gpu, op.groupid,
+ op.counterid);
+
+ if (copy_to_user(ptr, &op, sizeof(op)))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
/*
* Init/Cleanup:
*/
diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h
index 06dfaabbfcfe..3fac423929c5 100644
--- a/drivers/gpu/drm/msm/msm_gpu.h
+++ b/drivers/gpu/drm/msm/msm_gpu.h
@@ -71,6 +71,10 @@ struct msm_gpu_funcs {
void (*show)(struct msm_gpu *gpu, struct seq_file *m);
#endif
int (*snapshot)(struct msm_gpu *gpu, struct msm_snapshot *snapshot);
+ int (*get_counter)(struct msm_gpu *gpu, u32 groupid, u32 countable,
+ u32 *lo, u32 *hi);
+ void (*put_counter)(struct msm_gpu *gpu, u32 groupid, int counterid);
+ u64 (*read_counter)(struct msm_gpu *gpu, u32 groupid, int counterid);
};
struct msm_gpu {
@@ -258,4 +262,16 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev);
void __init adreno_register(void);
void __exit adreno_unregister(void);
+int msm_gpu_counter_get(struct msm_gpu *gpu, struct drm_msm_counter *data,
+ struct msm_file_private *ctx);
+
+int msm_gpu_counter_put(struct msm_gpu *gpu, struct drm_msm_counter *data,
+ struct msm_file_private *ctx);
+
+void msm_gpu_cleanup_counters(struct msm_gpu *gpu,
+ struct msm_file_private *ctx);
+
+u64 msm_gpu_counter_read(struct msm_gpu *gpu,
+ struct drm_msm_counter_read *data);
+
#endif /* __MSM_GPU_H__ */
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index 04cec0da5d1e..8901228b5d5d 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -205,8 +205,8 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y)
}
if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) ||
- x >= (crtc->x + crtc->mode.crtc_hdisplay) ||
- y >= (crtc->y + crtc->mode.crtc_vdisplay))
+ x >= (crtc->x + crtc->mode.hdisplay) ||
+ y >= (crtc->y + crtc->mode.vdisplay))
goto out_of_bounds;
x += xorigin;
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 4ae8b56b1847..037c38bb5333 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -1621,7 +1621,6 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
struct ttm_buffer_object *bo;
int ret = -EBUSY;
int put_count;
- uint32_t swap_placement = (TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM);
spin_lock(&glob->lru_lock);
list_for_each_entry(bo, &glob->swap_lru, swap) {
@@ -1657,7 +1656,8 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
if (unlikely(ret != 0))
goto out;
- if ((bo->mem.placement & swap_placement) != swap_placement) {
+ if (bo->mem.mem_type != TTM_PL_SYSTEM ||
+ bo->ttm->caching_state != tt_cached) {
struct ttm_mem_reg evict_mem;
evict_mem = bo->mem;
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 63194a9a7189..57c191798699 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -219,7 +219,7 @@ int hv_init(void)
/* See if the hypercall page is already set */
rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
- virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_EXEC);
+ virtaddr = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL_RX);
if (!virtaddr)
goto cleanup;
@@ -422,7 +422,7 @@ int hv_synic_alloc(void)
goto err;
}
- for_each_online_cpu(cpu) {
+ for_each_present_cpu(cpu) {
hv_context.event_dpc[cpu] = kmalloc(size, GFP_ATOMIC);
if (hv_context.event_dpc[cpu] == NULL) {
pr_err("Unable to allocate event dpc\n");
@@ -461,6 +461,8 @@ int hv_synic_alloc(void)
pr_err("Unable to allocate post msg page\n");
goto err;
}
+
+ INIT_LIST_HEAD(&hv_context.percpu_list[cpu]);
}
return 0;
@@ -485,7 +487,7 @@ void hv_synic_free(void)
int cpu;
kfree(hv_context.hv_numa_map);
- for_each_online_cpu(cpu)
+ for_each_present_cpu(cpu)
hv_synic_free_cpu(cpu);
}
@@ -555,8 +557,6 @@ void hv_synic_init(void *arg)
rdmsrl(HV_X64_MSR_VP_INDEX, vp_index);
hv_context.vp_index[cpu] = (u32)vp_index;
- INIT_LIST_HEAD(&hv_context.percpu_list[cpu]);
-
/*
* Register the per-cpu clockevent source.
*/
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index c37a71e13de0..1fb02dcbc500 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -61,6 +61,7 @@ static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
static const char fcopy_devname[] = "vmbus/hv_fcopy";
static u8 *recv_buffer;
static struct hvutil_transport *hvt;
+static struct completion release_event;
/*
* This state maintains the version number registered by the daemon.
*/
@@ -312,12 +313,14 @@ static void fcopy_on_reset(void)
if (cancel_delayed_work_sync(&fcopy_timeout_work))
fcopy_respond_to_host(HV_E_FAIL);
+ complete(&release_event);
}
int hv_fcopy_init(struct hv_util_service *srv)
{
recv_buffer = srv->recv_buffer;
+ init_completion(&release_event);
/*
* When this driver loads, the user level daemon that
* processes the host requests may not yet be running.
@@ -339,4 +342,5 @@ void hv_fcopy_deinit(void)
fcopy_transaction.state = HVUTIL_DEVICE_DYING;
cancel_delayed_work_sync(&fcopy_timeout_work);
hvutil_transport_destroy(hvt);
+ wait_for_completion(&release_event);
}
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 2a3420c4ca59..ce4d3a935491 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -86,6 +86,7 @@ static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
static const char kvp_devname[] = "vmbus/hv_kvp";
static u8 *recv_buffer;
static struct hvutil_transport *hvt;
+static struct completion release_event;
/*
* Register the kernel component with the user-level daemon.
* As part of this registration, pass the LIC version number.
@@ -682,6 +683,7 @@ static void kvp_on_reset(void)
if (cancel_delayed_work_sync(&kvp_timeout_work))
kvp_respond_to_host(NULL, HV_E_FAIL);
kvp_transaction.state = HVUTIL_DEVICE_INIT;
+ complete(&release_event);
}
int
@@ -689,6 +691,7 @@ hv_kvp_init(struct hv_util_service *srv)
{
recv_buffer = srv->recv_buffer;
+ init_completion(&release_event);
/*
* When this driver loads, the user level daemon that
* processes the host requests may not yet be running.
@@ -711,4 +714,5 @@ void hv_kvp_deinit(void)
cancel_delayed_work_sync(&kvp_timeout_work);
cancel_work_sync(&kvp_sendkey_work);
hvutil_transport_destroy(hvt);
+ wait_for_completion(&release_event);
}
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c
index 81882d4848bd..faad79ae318a 100644
--- a/drivers/hv/hv_snapshot.c
+++ b/drivers/hv/hv_snapshot.c
@@ -66,6 +66,7 @@ static int dm_reg_value;
static const char vss_devname[] = "vmbus/hv_vss";
static __u8 *recv_buffer;
static struct hvutil_transport *hvt;
+static struct completion release_event;
static void vss_send_op(struct work_struct *dummy);
static void vss_timeout_func(struct work_struct *dummy);
@@ -326,11 +327,13 @@ static void vss_on_reset(void)
if (cancel_delayed_work_sync(&vss_timeout_work))
vss_respond_to_host(HV_E_FAIL);
vss_transaction.state = HVUTIL_DEVICE_INIT;
+ complete(&release_event);
}
int
hv_vss_init(struct hv_util_service *srv)
{
+ init_completion(&release_event);
if (vmbus_proto_version < VERSION_WIN8_1) {
pr_warn("Integration service 'Backup (volume snapshot)'"
" not supported on this host version.\n");
@@ -360,4 +363,5 @@ void hv_vss_deinit(void)
cancel_delayed_work_sync(&vss_timeout_work);
cancel_work_sync(&vss_send_op_work);
hvutil_transport_destroy(hvt);
+ wait_for_completion(&release_event);
}
diff --git a/drivers/i2c/busses/i2c-msm-v2.c b/drivers/i2c/busses/i2c-msm-v2.c
index bf2a1dd7cf15..7f98d9f527b9 100644
--- a/drivers/i2c/busses/i2c-msm-v2.c
+++ b/drivers/i2c/busses/i2c-msm-v2.c
@@ -1151,12 +1151,20 @@ static void i2c_msm_dma_xfer_unprepare(struct i2c_msm_ctrl *ctrl)
buf_itr->dma_dir);
}
-static void i2c_msm_dma_callback_xfer_complete(void *dma_async_param)
+static void i2c_msm_dma_callback_tx_complete(void *dma_async_param)
{
struct i2c_msm_ctrl *ctrl = dma_async_param;
+
complete(&ctrl->xfer.complete);
}
+static void i2c_msm_dma_callback_rx_complete(void *dma_async_param)
+{
+ struct i2c_msm_ctrl *ctrl = dma_async_param;
+
+ complete(&ctrl->xfer.rx_complete);
+}
+
/*
* i2c_msm_dma_xfer_process: Queue transfers to DMA
* @pre 1)QUP is in run state. 2) i2c_msm_dma_xfer_prepare() was called.
@@ -1269,14 +1277,16 @@ static int i2c_msm_dma_xfer_process(struct i2c_msm_ctrl *ctrl)
}
/* callback defined for tx dma desc */
- dma_desc_tx->callback = i2c_msm_dma_callback_xfer_complete;
+ dma_desc_tx->callback = i2c_msm_dma_callback_tx_complete;
dma_desc_tx->callback_param = ctrl;
dmaengine_submit(dma_desc_tx);
dma_async_issue_pending(tx->dma_chan);
/* queue the rx dma desc */
dma_desc_rx = dmaengine_prep_slave_sg(rx->dma_chan, sg_rx,
- sg_rx_itr - sg_rx, rx->dir, 0);
+ sg_rx_itr - sg_rx, rx->dir,
+ (SPS_IOVEC_FLAG_EOT |
+ SPS_IOVEC_FLAG_NWD));
if (dma_desc_rx < 0) {
dev_err(ctrl->dev,
"error dmaengine_prep_slave_sg rx:%ld\n",
@@ -1285,6 +1295,8 @@ static int i2c_msm_dma_xfer_process(struct i2c_msm_ctrl *ctrl)
goto dma_xfer_end;
}
+ dma_desc_rx->callback = i2c_msm_dma_callback_rx_complete;
+ dma_desc_rx->callback_param = ctrl;
dmaengine_submit(dma_desc_rx);
dma_async_issue_pending(rx->dma_chan);
@@ -1297,6 +1309,8 @@ static int i2c_msm_dma_xfer_process(struct i2c_msm_ctrl *ctrl)
}
ret = i2c_msm_xfer_wait_for_completion(ctrl, &ctrl->xfer.complete);
+ if (!ret && ctrl->xfer.rx_cnt)
+ i2c_msm_xfer_wait_for_completion(ctrl, &ctrl->xfer.rx_complete);
dma_xfer_end:
/* free scatter-gather lists */
@@ -2054,13 +2068,14 @@ static int i2c_msm_xfer_wait_for_completion(struct i2c_msm_ctrl *ctrl,
long time_left;
int ret = 0;
- time_left = wait_for_completion_timeout(complete, xfer->timeout);
+ time_left = wait_for_completion_timeout(complete,
+ xfer->timeout);
if (!time_left) {
xfer->err = I2C_MSM_ERR_TIMEOUT;
i2c_msm_dbg_dump_diag(ctrl, false, 0, 0);
ret = -EIO;
i2c_msm_prof_evnt_add(ctrl, MSM_ERR, I2C_MSM_COMPLT_FL,
- xfer->timeout, time_left, 0);
+ xfer->timeout, time_left, 0);
} else {
/* return an error if one detected by ISR */
if (xfer->err)
@@ -2327,6 +2342,8 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
xfer->tx_ovrhd_cnt = 0;
atomic_set(&xfer->event_cnt, 0);
init_completion(&xfer->complete);
+ init_completion(&xfer->rx_complete);
+
xfer->cur_buf.is_init = false;
xfer->cur_buf.msg_idx = 0;
diff --git a/drivers/iio/adc/qcom-rradc.c b/drivers/iio/adc/qcom-rradc.c
index 57145ea72e90..537cca877f66 100644
--- a/drivers/iio/adc/qcom-rradc.c
+++ b/drivers/iio/adc/qcom-rradc.c
@@ -38,6 +38,7 @@
#define FG_ADC_RR_FAKE_BATT_HIGH_MSB 0x5B
#define FG_ADC_RR_BATT_ID_CTRL 0x60
+#define FG_ADC_RR_BATT_ID_CTRL_CHANNEL_CONV BIT(0)
#define FG_ADC_RR_BATT_ID_TRIGGER 0x61
#define FG_ADC_RR_BATT_ID_TRIGGER_CTL BIT(0)
#define FG_ADC_RR_BATT_ID_STS 0x62
@@ -163,11 +164,6 @@
#define FG_ADC_RR_DIE_TEMP_SLOPE 2
#define FG_ADC_RR_DIE_TEMP_OFFSET_MILLI_DEGC 25000
-#define FAB_ID_GF 0x30
-#define FAB_ID_SMIC 0x11
-#define FAB_ID_660_GF 0x0
-#define FAB_ID_660_TSMC 0x2
-#define FAB_ID_660_MX 0x3
#define FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV 1303168
#define FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C 3784
#define FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV 1338433
@@ -401,11 +397,11 @@ static int rradc_get_660_fab_coeff(struct rradc_chip *chip,
int64_t *offset, int64_t *slope)
{
switch (chip->pmic_fab_id->fab_id) {
- case FAB_ID_660_GF:
+ case PM660_FAB_ID_GF:
*offset = FG_ADC_RR_CHG_TEMP_660_GF_OFFSET_UV;
*slope = FG_RR_CHG_TEMP_660_GF_SLOPE_UV_PER_C;
break;
- case FAB_ID_660_TSMC:
+ case PM660_FAB_ID_TSMC:
*offset = FG_ADC_RR_CHG_TEMP_660_SMIC_OFFSET_UV;
*slope = FG_RR_CHG_TEMP_660_SMIC_SLOPE_UV_PER_C;
break;
@@ -421,11 +417,11 @@ static int rradc_get_8998_fab_coeff(struct rradc_chip *chip,
int64_t *offset, int64_t *slope)
{
switch (chip->pmic_fab_id->fab_id) {
- case FAB_ID_GF:
+ case PMI8998_FAB_ID_GF:
*offset = FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV;
*slope = FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C;
break;
- case FAB_ID_SMIC:
+ case PMI8998_FAB_ID_SMIC:
*offset = FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV;
*slope = FG_ADC_RR_CHG_TEMP_SMIC_SLOPE_UV_PER_C;
break;
@@ -753,6 +749,75 @@ static int rradc_read_channel_with_continuous_mode(struct rradc_chip *chip,
return rc;
}
+static int rradc_enable_batt_id_channel(struct rradc_chip *chip, bool enable)
+{
+ int rc = 0;
+
+ if (enable) {
+ rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_CTRL,
+ FG_ADC_RR_BATT_ID_CTRL_CHANNEL_CONV,
+ FG_ADC_RR_BATT_ID_CTRL_CHANNEL_CONV);
+ if (rc < 0) {
+ pr_err("Enabling BATT ID channel failed:%d\n", rc);
+ return rc;
+ }
+ } else {
+ rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_CTRL,
+ FG_ADC_RR_BATT_ID_CTRL_CHANNEL_CONV, 0);
+ if (rc < 0) {
+ pr_err("Disabling BATT ID channel failed:%d\n", rc);
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
+static int rradc_do_batt_id_conversion(struct rradc_chip *chip,
+ struct rradc_chan_prop *prop, u16 *data, u8 *buf)
+{
+ int rc = 0, ret = 0;
+
+ rc = rradc_enable_batt_id_channel(chip, true);
+ if (rc < 0) {
+ pr_err("Enabling BATT ID channel failed:%d\n", rc);
+ return rc;
+ }
+
+ rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_TRIGGER,
+ FG_ADC_RR_BATT_ID_TRIGGER_CTL,
+ FG_ADC_RR_BATT_ID_TRIGGER_CTL);
+ if (rc < 0) {
+ pr_err("BATT_ID trigger set failed:%d\n", rc);
+ ret = rc;
+ rc = rradc_enable_batt_id_channel(chip, false);
+ if (rc < 0)
+ pr_err("Disabling BATT ID channel failed:%d\n", rc);
+ return ret;
+ }
+
+ rc = rradc_read_channel_with_continuous_mode(chip, prop, buf);
+ if (rc < 0) {
+ pr_err("Error reading in continuous mode:%d\n", rc);
+ ret = rc;
+ }
+
+ rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_TRIGGER,
+ FG_ADC_RR_BATT_ID_TRIGGER_CTL, 0);
+ if (rc < 0) {
+ pr_err("BATT_ID trigger re-set failed:%d\n", rc);
+ ret = rc;
+ }
+
+ rc = rradc_enable_batt_id_channel(chip, false);
+ if (rc < 0) {
+ pr_err("Disabling BATT ID channel failed:%d\n", rc);
+ ret = rc;
+ }
+
+ return ret;
+}
+
static int rradc_do_conversion(struct rradc_chip *chip,
struct rradc_chan_prop *prop, u16 *data)
{
@@ -765,24 +830,9 @@ static int rradc_do_conversion(struct rradc_chip *chip,
switch (prop->channel) {
case RR_ADC_BATT_ID:
- rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_TRIGGER,
- FG_ADC_RR_BATT_ID_TRIGGER_CTL,
- FG_ADC_RR_BATT_ID_TRIGGER_CTL);
- if (rc < 0) {
- pr_err("BATT_ID trigger set failed:%d\n", rc);
- goto fail;
- }
-
- rc = rradc_read_channel_with_continuous_mode(chip, prop, buf);
- if (rc < 0) {
- pr_err("Error reading in continuous mode:%d\n", rc);
- goto fail;
- }
-
- rc = rradc_masked_write(chip, FG_ADC_RR_BATT_ID_TRIGGER,
- FG_ADC_RR_BATT_ID_TRIGGER_CTL, 0);
+ rc = rradc_do_batt_id_conversion(chip, prop, data, buf);
if (rc < 0) {
- pr_err("BATT_ID trigger re-set failed:%d\n", rc);
+ pr_err("Battery ID conversion failed:%d\n", rc);
goto fail;
}
break;
diff --git a/drivers/iio/adc/qcom-tadc.c b/drivers/iio/adc/qcom-tadc.c
index e30361eb4338..054dfcc8556a 100644
--- a/drivers/iio/adc/qcom-tadc.c
+++ b/drivers/iio/adc/qcom-tadc.c
@@ -18,7 +18,12 @@
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/power_supply.h>
+#include <linux/pmic-voter.h>
+#define USB_PRESENT_VOTER "USB_PRESENT_VOTER"
+#define SLEEP_VOTER "SLEEP_VOTER"
+#define SHUTDOWN_VOTER "SHUTDOWN_VOTER"
#define TADC_REVISION1_REG 0x00
#define TADC_REVISION2_REG 0x01
#define TADC_REVISION3_REG 0x02
@@ -54,6 +59,7 @@
#define TADC_CH7_ADC_HI_REG(chip) (chip->tadc_base + 0x73)
#define TADC_CH8_ADC_LO_REG(chip) (chip->tadc_base + 0x74)
#define TADC_CH8_ADC_HI_REG(chip) (chip->tadc_base + 0x75)
+#define TADC_ADC_DIRECT_TST(chip) (chip->tadc_base + 0xE7)
/* TADC_CMP register definitions */
#define TADC_CMP_THR1_CMP_REG(chip) (chip->tadc_cmp_base + 0x51)
@@ -218,6 +224,10 @@ struct tadc_chip {
struct completion eoc_complete;
struct mutex write_lock;
struct mutex conv_lock;
+ struct power_supply *usb_psy;
+ struct votable *tadc_disable_votable;
+ struct work_struct status_change_work;
+ struct notifier_block nb;
};
struct tadc_pt {
@@ -275,7 +285,7 @@ static bool tadc_is_reg_locked(struct tadc_chip *chip, u16 reg)
if ((reg & 0xFF00) == chip->tadc_cmp_base)
return true;
- if (reg == TADC_HWTRIG_CONV_CH_EN_REG(chip))
+ if (reg >= TADC_HWTRIG_CONV_CH_EN_REG(chip))
return true;
return false;
@@ -481,7 +491,7 @@ static int tadc_do_conversion(struct tadc_chip *chip, u8 channels, s16 *adc)
{
unsigned long timeout, timeleft;
u8 val[TADC_NUM_CH * 2];
- int rc, i;
+ int rc = 0, i;
mutex_lock(&chip->conv_lock);
rc = tadc_read(chip, TADC_MBG_ERR_REG(chip), val, 1);
@@ -490,6 +500,15 @@ static int tadc_do_conversion(struct tadc_chip *chip, u8 channels, s16 *adc)
goto unlock;
}
+ reinit_completion(&chip->eoc_complete);
+
+ if (get_effective_result(chip->tadc_disable_votable)) {
+ /* leave it back in completed state */
+ complete_all(&chip->eoc_complete);
+ rc = -ENODATA;
+ goto unlock;
+ }
+
if (val[0] != 0) {
tadc_write(chip, TADC_EN_CTL_REG(chip), 0);
tadc_write(chip, TADC_EN_CTL_REG(chip), 0x80);
@@ -511,6 +530,10 @@ static int tadc_do_conversion(struct tadc_chip *chip, u8 channels, s16 *adc)
goto unlock;
}
+ /*
+ * check one last time if the channel we are requesting
+ * has completed conversion
+ */
if (val[0] != channels) {
rc = -ETIMEDOUT;
goto unlock;
@@ -526,7 +549,8 @@ static int tadc_do_conversion(struct tadc_chip *chip, u8 channels, s16 *adc)
for (i = 0; i < TADC_NUM_CH; i++)
adc[i] = (s16)(val[i * 2] | (u16)val[i * 2 + 1] << 8);
- rc = jiffies_to_msecs(timeout - timeleft);
+ pr_debug("Conversion time for channels 0x%x = %dms\n", channels,
+ jiffies_to_msecs(timeout - timeleft));
unlock:
mutex_unlock(&chip->conv_lock);
@@ -599,12 +623,17 @@ static int tadc_read_raw(struct iio_dev *indio_dev,
break;
default:
rc = tadc_do_conversion(chip, BIT(chan->channel), adc);
- if (rc >= 0)
- *val = adc[chan->channel];
+ if (rc < 0) {
+ if (rc != -ENODATA)
+ pr_err("Couldn't read battery current and voltage channels rc=%d\n",
+ rc);
+ return rc;
+ }
+ *val = adc[chan->channel];
break;
}
- if (rc < 0) {
+ if (rc < 0 && rc != -ENODATA) {
pr_err("Couldn't read channel %d\n", chan->channel);
return rc;
}
@@ -636,7 +665,7 @@ static int tadc_read_raw(struct iio_dev *indio_dev,
case TADC_BATT_P:
rc = tadc_do_conversion(chip,
BIT(TADC_BATT_I) | BIT(TADC_BATT_V), adc);
- if (rc < 0) {
+ if (rc < 0 && rc != -ENODATA) {
pr_err("Couldn't read battery current and voltage channels rc=%d\n",
rc);
return rc;
@@ -647,7 +676,7 @@ static int tadc_read_raw(struct iio_dev *indio_dev,
case TADC_INPUT_P:
rc = tadc_do_conversion(chip,
BIT(TADC_INPUT_I) | BIT(TADC_INPUT_V), adc);
- if (rc < 0) {
+ if (rc < 0 && rc != -ENODATA) {
pr_err("Couldn't read input current and voltage channels rc=%d\n",
rc);
return rc;
@@ -828,15 +857,130 @@ static int tadc_write_raw(struct iio_dev *indio_dev,
return 0;
}
-
static irqreturn_t handle_eoc(int irq, void *dev_id)
{
struct tadc_chip *chip = dev_id;
- complete(&chip->eoc_complete);
+ complete_all(&chip->eoc_complete);
return IRQ_HANDLED;
}
+static int tadc_disable_vote_callback(struct votable *votable,
+ void *data, int disable, const char *client)
+{
+ struct tadc_chip *chip = data;
+ int rc;
+ int timeout;
+ unsigned long timeleft;
+
+ if (disable) {
+ timeout = msecs_to_jiffies(CONVERSION_TIMEOUT_MS);
+ timeleft = wait_for_completion_timeout(&chip->eoc_complete,
+ timeout);
+ if (timeleft == 0)
+ pr_err("Timed out waiting for eoc, disabling hw conversions regardless\n");
+
+ rc = tadc_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip), 0x00);
+ if (rc < 0) {
+ pr_err("Couldn't disable hw conversions rc=%d\n", rc);
+ return rc;
+ }
+ rc = tadc_write(chip, TADC_ADC_DIRECT_TST(chip), 0x80);
+ if (rc < 0) {
+ pr_err("Couldn't enable direct test mode rc=%d\n", rc);
+ return rc;
+ }
+ } else {
+ rc = tadc_write(chip, TADC_ADC_DIRECT_TST(chip), 0x00);
+ if (rc < 0) {
+ pr_err("Couldn't disable direct test mode rc=%d\n", rc);
+ return rc;
+ }
+ rc = tadc_write(chip, TADC_HWTRIG_CONV_CH_EN_REG(chip), 0x07);
+ if (rc < 0) {
+ pr_err("Couldn't enable hw conversions rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ pr_debug("client: %s disable: %d\n", client, disable);
+ return 0;
+}
+
+static void status_change_work(struct work_struct *work)
+{
+ struct tadc_chip *chip = container_of(work,
+ struct tadc_chip, status_change_work);
+ union power_supply_propval pval = {0, };
+ int rc;
+
+ if (!chip->usb_psy)
+ chip->usb_psy = power_supply_get_by_name("usb");
+
+ if (!chip->usb_psy) {
+ /* treat usb is not present */
+ vote(chip->tadc_disable_votable, USB_PRESENT_VOTER, true, 0);
+ return;
+ }
+
+ rc = power_supply_get_property(chip->usb_psy,
+ POWER_SUPPLY_PROP_PRESENT, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get present status rc=%d\n", rc);
+ /* treat usb is not present */
+ vote(chip->tadc_disable_votable, USB_PRESENT_VOTER, true, 0);
+ return;
+ }
+
+ /* disable if usb is not present */
+ vote(chip->tadc_disable_votable, USB_PRESENT_VOTER, !pval.intval, 0);
+}
+
+static int tadc_notifier_call(struct notifier_block *nb,
+ unsigned long ev, void *v)
+{
+ struct power_supply *psy = v;
+ struct tadc_chip *chip = container_of(nb, struct tadc_chip, nb);
+
+ if (ev != PSY_EVENT_PROP_CHANGED)
+ return NOTIFY_OK;
+
+ if ((strcmp(psy->desc->name, "usb") == 0))
+ schedule_work(&chip->status_change_work);
+
+ return NOTIFY_OK;
+}
+
+static int tadc_register_notifier(struct tadc_chip *chip)
+{
+ int rc;
+
+ chip->nb.notifier_call = tadc_notifier_call;
+ rc = power_supply_reg_notifier(&chip->nb);
+ if (rc < 0) {
+ pr_err("Couldn't register psy notifier rc = %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int tadc_suspend(struct device *dev)
+{
+ struct tadc_chip *chip = dev_get_drvdata(dev);
+
+ vote(chip->tadc_disable_votable, SLEEP_VOTER, true, 0);
+ return 0;
+}
+
+static int tadc_resume(struct device *dev)
+{
+ struct tadc_chip *chip = dev_get_drvdata(dev);
+
+ vote(chip->tadc_disable_votable, SLEEP_VOTER, false, 0);
+ return 0;
+}
+
static int tadc_set_therm_table(struct tadc_chan_data *chan_data, u32 beta,
u32 rtherm)
{
@@ -1016,6 +1160,12 @@ static int tadc_probe(struct platform_device *pdev)
chip->dev = &pdev->dev;
init_completion(&chip->eoc_complete);
+ /*
+ * set the completion in "completed" state so disable of the tadc
+ * can progress
+ */
+ complete_all(&chip->eoc_complete);
+
rc = of_property_read_u32(node, "reg", &chip->tadc_base);
if (rc < 0) {
pr_err("Couldn't read base address rc=%d\n", rc);
@@ -1025,6 +1175,7 @@ static int tadc_probe(struct platform_device *pdev)
mutex_init(&chip->write_lock);
mutex_init(&chip->conv_lock);
+ INIT_WORK(&chip->status_change_work, status_change_work);
chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
if (!chip->regmap) {
pr_err("Couldn't get regmap\n");
@@ -1043,17 +1194,36 @@ static int tadc_probe(struct platform_device *pdev)
return rc;
}
+ chip->tadc_disable_votable = create_votable("SMB_TADC_DISABLE",
+ VOTE_SET_ANY,
+ tadc_disable_vote_callback,
+ chip);
+ if (IS_ERR(chip->tadc_disable_votable)) {
+ rc = PTR_ERR(chip->tadc_disable_votable);
+ return rc;
+ }
+ /* assume usb is not present */
+ vote(chip->tadc_disable_votable, USB_PRESENT_VOTER, true, 0);
+ vote(chip->tadc_disable_votable, SHUTDOWN_VOTER, false, 0);
+ vote(chip->tadc_disable_votable, SLEEP_VOTER, false, 0);
+
+ rc = tadc_register_notifier(chip);
+ if (rc < 0) {
+ pr_err("Couldn't register notifier=%d\n", rc);
+ goto destroy_votable;
+ }
+
irq = of_irq_get_byname(node, "eoc");
if (irq < 0) {
pr_err("Couldn't get eoc irq rc=%d\n", irq);
- return irq;
+ goto destroy_votable;
}
rc = devm_request_threaded_irq(chip->dev, irq, NULL, handle_eoc,
IRQF_ONESHOT, "eoc", chip);
if (rc < 0) {
pr_err("Couldn't request irq %d rc=%d\n", irq, rc);
- return rc;
+ goto destroy_votable;
}
indio_dev->dev.parent = chip->dev;
@@ -1066,17 +1236,37 @@ static int tadc_probe(struct platform_device *pdev)
rc = devm_iio_device_register(chip->dev, indio_dev);
if (rc < 0) {
pr_err("Couldn't register IIO device rc=%d\n", rc);
- return rc;
+ goto destroy_votable;
}
+ platform_set_drvdata(pdev, chip);
return 0;
+
+destroy_votable:
+ destroy_votable(chip->tadc_disable_votable);
+ return rc;
}
static int tadc_remove(struct platform_device *pdev)
{
+ struct tadc_chip *chip = platform_get_drvdata(pdev);
+
+ destroy_votable(chip->tadc_disable_votable);
return 0;
}
+static void tadc_shutdown(struct platform_device *pdev)
+{
+ struct tadc_chip *chip = platform_get_drvdata(pdev);
+
+ vote(chip->tadc_disable_votable, SHUTDOWN_VOTER, true, 0);
+}
+
+static const struct dev_pm_ops tadc_pm_ops = {
+ .resume = tadc_resume,
+ .suspend = tadc_suspend,
+};
+
static const struct of_device_id tadc_match_table[] = {
{ .compatible = "qcom,tadc" },
{ }
@@ -1084,12 +1274,14 @@ static const struct of_device_id tadc_match_table[] = {
MODULE_DEVICE_TABLE(of, tadc_match_table);
static struct platform_driver tadc_driver = {
- .driver = {
+ .driver = {
.name = "qcom-tadc",
.of_match_table = tadc_match_table,
+ .pm = &tadc_pm_ops,
},
- .probe = tadc_probe,
- .remove = tadc_remove,
+ .probe = tadc_probe,
+ .remove = tadc_remove,
+ .shutdown = tadc_shutdown,
};
module_platform_driver(tadc_driver);
diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c
index a0d7deeac62f..3f90985d545e 100644
--- a/drivers/iio/pressure/mpl115.c
+++ b/drivers/iio/pressure/mpl115.c
@@ -136,6 +136,7 @@ static const struct iio_chan_spec mpl115_channels[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type =
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE),
},
};
diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c
index 01b2e0b18878..0f5b8767ec2e 100644
--- a/drivers/iio/pressure/mpl3115.c
+++ b/drivers/iio/pressure/mpl3115.c
@@ -182,7 +182,7 @@ static const struct iio_chan_spec mpl3115_channels[] = {
{
.type = IIO_PRESSURE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
- BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -195,7 +195,7 @@ static const struct iio_chan_spec mpl3115_channels[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
- BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 1,
.scan_type = {
.sign = 's',
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index c9dcad6a53bf..3f5741a3e728 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -3349,6 +3349,9 @@ static int cma_accept_iw(struct rdma_id_private *id_priv,
struct iw_cm_conn_param iw_param;
int ret;
+ if (!conn_param)
+ return -EINVAL;
+
ret = cma_modify_qp_rtr(id_priv, conn_param);
if (ret)
return ret;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 3ba7de5f9379..2018d24344de 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -1488,12 +1488,14 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr,
ret = ipoib_set_mode(dev, buf);
- rtnl_unlock();
-
- if (!ret)
- return count;
+ /* The assumption is that the function ipoib_set_mode returned
+ * with the rtnl held by it, if not the value -EBUSY returned,
+ * then no need to rtnl_unlock
+ */
+ if (ret != -EBUSY)
+ rtnl_unlock();
- return ret;
+ return (!ret || ret == -EBUSY) ? count : ret;
}
static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, show_mode, set_mode);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 8a4d10452d61..8efcff1beb8f 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -464,8 +464,7 @@ int ipoib_set_mode(struct net_device *dev, const char *buf)
priv->tx_wr.wr.send_flags &= ~IB_SEND_IP_CSUM;
ipoib_flush_paths(dev);
- rtnl_lock();
- return 0;
+ return (!rtnl_trylock()) ? -EBUSY : 0;
}
if (!strcmp(buf, "datagram\n")) {
@@ -474,8 +473,7 @@ int ipoib_set_mode(struct net_device *dev, const char *buf)
dev_set_mtu(dev, min(priv->mcast_mtu, dev->mtu));
rtnl_unlock();
ipoib_flush_paths(dev);
- rtnl_lock();
- return 0;
+ return (!rtnl_trylock()) ? -EBUSY : 0;
}
return -EINVAL;
@@ -628,6 +626,14 @@ void ipoib_mark_paths_invalid(struct net_device *dev)
spin_unlock_irq(&priv->lock);
}
+static void push_pseudo_header(struct sk_buff *skb, const char *daddr)
+{
+ struct ipoib_pseudo_header *phdr;
+
+ phdr = (struct ipoib_pseudo_header *)skb_push(skb, sizeof(*phdr));
+ memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
+}
+
void ipoib_flush_paths(struct net_device *dev)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -852,8 +858,7 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,
}
if (skb_queue_len(&neigh->queue) <
IPOIB_MAX_PATH_REC_QUEUE) {
- /* put pseudoheader back on for next time */
- skb_push(skb, IPOIB_PSEUDO_LEN);
+ push_pseudo_header(skb, neigh->daddr);
__skb_queue_tail(&neigh->queue, skb);
} else {
ipoib_warn(priv, "queue length limit %d. Packet drop.\n",
@@ -871,10 +876,12 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr,
if (!path->query && path_rec_start(dev, path))
goto err_path;
- if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE)
+ if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
+ push_pseudo_header(skb, neigh->daddr);
__skb_queue_tail(&neigh->queue, skb);
- else
+ } else {
goto err_drop;
+ }
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -910,8 +917,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
}
if (path) {
if (skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
- /* put pseudoheader back on for next time */
- skb_push(skb, IPOIB_PSEUDO_LEN);
+ push_pseudo_header(skb, phdr->hwaddr);
__skb_queue_tail(&path->queue, skb);
} else {
++dev->stats.tx_dropped;
@@ -943,8 +949,7 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev,
return;
} else if ((path->query || !path_rec_start(dev, path)) &&
skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
- /* put pseudoheader back on for next time */
- skb_push(skb, IPOIB_PSEUDO_LEN);
+ push_pseudo_header(skb, phdr->hwaddr);
__skb_queue_tail(&path->queue, skb);
} else {
++dev->stats.tx_dropped;
@@ -1025,8 +1030,7 @@ send_using_neigh:
}
if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
- /* put pseudoheader back on for next time */
- skb_push(skb, sizeof(*phdr));
+ push_pseudo_header(skb, phdr->hwaddr);
spin_lock_irqsave(&priv->lock, flags);
__skb_queue_tail(&neigh->queue, skb);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1058,7 +1062,6 @@ static int ipoib_hard_header(struct sk_buff *skb,
unsigned short type,
const void *daddr, const void *saddr, unsigned len)
{
- struct ipoib_pseudo_header *phdr;
struct ipoib_header *header;
header = (struct ipoib_header *) skb_push(skb, sizeof *header);
@@ -1071,8 +1074,7 @@ static int ipoib_hard_header(struct sk_buff *skb,
* destination address into skb hard header so we can figure out where
* to send the packet later.
*/
- phdr = (struct ipoib_pseudo_header *) skb_push(skb, sizeof(*phdr));
- memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
+ push_pseudo_header(skb, daddr);
return IPOIB_HARD_LEN;
}
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 5f0f4fc58f43..e397f1b0af09 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1787,17 +1787,24 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp)
if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) {
spin_lock_irqsave(&ch->lock, flags);
ch->req_lim += be32_to_cpu(rsp->req_lim_delta);
+ if (rsp->tag == ch->tsk_mgmt_tag) {
+ ch->tsk_mgmt_status = -1;
+ if (be32_to_cpu(rsp->resp_data_len) >= 4)
+ ch->tsk_mgmt_status = rsp->data[3];
+ complete(&ch->tsk_mgmt_done);
+ } else {
+ shost_printk(KERN_ERR, target->scsi_host,
+ "Received tsk mgmt response too late for tag %#llx\n",
+ rsp->tag);
+ }
spin_unlock_irqrestore(&ch->lock, flags);
-
- ch->tsk_mgmt_status = -1;
- if (be32_to_cpu(rsp->resp_data_len) >= 4)
- ch->tsk_mgmt_status = rsp->data[3];
- complete(&ch->tsk_mgmt_done);
} else {
scmnd = scsi_host_find_tag(target->scsi_host, rsp->tag);
- if (scmnd) {
+ if (scmnd && scmnd->host_scribble) {
req = (void *)scmnd->host_scribble;
scmnd = srp_claim_req(ch, req, NULL, scmnd);
+ } else {
+ scmnd = NULL;
}
if (!scmnd) {
shost_printk(KERN_ERR, target->scsi_host,
@@ -2469,19 +2476,18 @@ srp_change_queue_depth(struct scsi_device *sdev, int qdepth)
}
static int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, u64 lun,
- u8 func)
+ u8 func, u8 *status)
{
struct srp_target_port *target = ch->target;
struct srp_rport *rport = target->rport;
struct ib_device *dev = target->srp_host->srp_dev->dev;
struct srp_iu *iu;
struct srp_tsk_mgmt *tsk_mgmt;
+ int res;
if (!ch->connected || target->qp_in_error)
return -1;
- init_completion(&ch->tsk_mgmt_done);
-
/*
* Lock the rport mutex to avoid that srp_create_ch_ib() is
* invoked while a task management function is being sent.
@@ -2504,10 +2510,16 @@ static int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, u64 lun,
tsk_mgmt->opcode = SRP_TSK_MGMT;
int_to_scsilun(lun, &tsk_mgmt->lun);
- tsk_mgmt->tag = req_tag | SRP_TAG_TSK_MGMT;
tsk_mgmt->tsk_mgmt_func = func;
tsk_mgmt->task_tag = req_tag;
+ spin_lock_irq(&ch->lock);
+ ch->tsk_mgmt_tag = (ch->tsk_mgmt_tag + 1) | SRP_TAG_TSK_MGMT;
+ tsk_mgmt->tag = ch->tsk_mgmt_tag;
+ spin_unlock_irq(&ch->lock);
+
+ init_completion(&ch->tsk_mgmt_done);
+
ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt,
DMA_TO_DEVICE);
if (srp_post_send(ch, iu, sizeof(*tsk_mgmt))) {
@@ -2516,13 +2528,15 @@ static int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, u64 lun,
return -1;
}
+ res = wait_for_completion_timeout(&ch->tsk_mgmt_done,
+ msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS));
+ if (res > 0 && status)
+ *status = ch->tsk_mgmt_status;
mutex_unlock(&rport->mutex);
- if (!wait_for_completion_timeout(&ch->tsk_mgmt_done,
- msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS)))
- return -1;
+ WARN_ON_ONCE(res < 0);
- return 0;
+ return res > 0 ? 0 : -1;
}
static int srp_abort(struct scsi_cmnd *scmnd)
@@ -2548,7 +2562,7 @@ static int srp_abort(struct scsi_cmnd *scmnd)
shost_printk(KERN_ERR, target->scsi_host,
"Sending SRP abort for tag %#x\n", tag);
if (srp_send_tsk_mgmt(ch, tag, scmnd->device->lun,
- SRP_TSK_ABORT_TASK) == 0)
+ SRP_TSK_ABORT_TASK, NULL) == 0)
ret = SUCCESS;
else if (target->rport->state == SRP_RPORT_LOST)
ret = FAST_IO_FAIL;
@@ -2566,14 +2580,15 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
struct srp_target_port *target = host_to_target(scmnd->device->host);
struct srp_rdma_ch *ch;
int i;
+ u8 status;
shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n");
ch = &target->ch[0];
if (srp_send_tsk_mgmt(ch, SRP_TAG_NO_REQ, scmnd->device->lun,
- SRP_TSK_LUN_RESET))
+ SRP_TSK_LUN_RESET, &status))
return FAILED;
- if (ch->tsk_mgmt_status)
+ if (status)
return FAILED;
for (i = 0; i < target->ch_count; i++) {
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index f6af531f9f32..109eea94d0f9 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -168,6 +168,7 @@ struct srp_rdma_ch {
int max_ti_iu_len;
int comp_vector;
+ u64 tsk_mgmt_tag;
struct completion tsk_mgmt_done;
u8 tsk_mgmt_status;
bool connected;
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index cf29f2756b84..c93dd193a496 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -3,6 +3,7 @@
*
* Copyright 2005 Phil Blundell
* Copyright 2010, 2011 David Jander <david@protonic.nl>
+ * 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 as
@@ -32,6 +33,7 @@
#include <linux/of_irq.h>
#include <linux/spinlock.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/syscore_ops.h>
struct gpio_button_data {
const struct gpio_keys_button *button;
@@ -57,6 +59,11 @@ struct gpio_keys_drvdata {
struct gpio_button_data data[0];
};
+static struct device *global_dev;
+static struct syscore_ops gpio_keys_syscore_pm_ops;
+
+static void gpio_keys_syscore_resume(void);
+
/*
* SYSFS interface for enabling/disabling keys and switches:
*
@@ -343,14 +350,14 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
const struct gpio_keys_button *button = bdata->button;
struct input_dev *input = bdata->input;
unsigned int type = button->type ?: EV_KEY;
- int state = gpio_get_value_cansleep(button->gpio);
+ int state;
+ state = (__gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
if (state < 0) {
dev_err(input->dev.parent, "failed to get gpio state\n");
return;
}
- state = (state ? 1 : 0) ^ button->active_low;
if (type == EV_ABS) {
if (state)
input_event(input, type, button->code, button->value);
@@ -664,6 +671,8 @@ gpio_keys_get_devtree_pdata(struct device *dev)
pdata->nbuttons = nbuttons;
pdata->rep = !!of_get_property(node, "autorepeat", NULL);
+ pdata->name = of_get_property(node, "input-name", NULL);
+ pdata->use_syscore = of_property_read_bool(node, "use-syscore");
i = 0;
for_each_child_of_node(node, pp) {
@@ -710,7 +719,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL);
if (of_property_read_u32(pp, "debounce-interval",
- &button->debounce_interval))
+ &button->debounce_interval))
button->debounce_interval = 5;
}
@@ -767,6 +776,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ global_dev = dev;
ddata->pdata = pdata;
ddata->input = input;
mutex_init(&ddata->disable_lock);
@@ -835,6 +845,11 @@ static int gpio_keys_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, wakeup);
+ if (pdata->use_syscore)
+ gpio_keys_syscore_pm_ops.resume = gpio_keys_syscore_resume;
+
+ register_syscore_ops(&gpio_keys_syscore_pm_ops);
+
return 0;
err_remove_group:
@@ -857,6 +872,7 @@ err_setup_key:
static int gpio_keys_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
+ unregister_syscore_ops(&gpio_keys_syscore_pm_ops);
device_init_wakeup(&pdev->dev, 0);
@@ -864,6 +880,41 @@ static int gpio_keys_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
+static void gpio_keys_syscore_resume(void)
+{
+ struct gpio_keys_drvdata *ddata = dev_get_drvdata(global_dev);
+ struct input_dev *input = ddata->input;
+ struct gpio_button_data *bdata = NULL;
+ int error = 0;
+ int i;
+
+ if (ddata->key_pinctrl) {
+ error = gpio_keys_pinctrl_configure(ddata, true);
+ if (error) {
+ dev_err(global_dev, "failed to put the pin in resume state\n");
+ return;
+ }
+ }
+
+ if (device_may_wakeup(global_dev)) {
+ for (i = 0; i < ddata->pdata->nbuttons; i++) {
+ bdata = &ddata->data[i];
+ if (bdata->button->wakeup)
+ disable_irq_wake(bdata->irq);
+ }
+ } else {
+ mutex_lock(&input->mutex);
+ if (input->users)
+ error = gpio_keys_open(input);
+ mutex_unlock(&input->mutex);
+ }
+
+ if (error)
+ return;
+
+ gpio_keys_report_state(ddata);
+}
+
static int gpio_keys_suspend(struct device *dev)
{
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
@@ -901,6 +952,11 @@ static int gpio_keys_resume(struct device *dev)
int error = 0;
int i;
+ if (ddata->pdata->use_syscore == true) {
+ dev_dbg(global_dev, "Using syscore resume, no need of this resume.\n");
+ return 0;
+ }
+
if (ddata->key_pinctrl) {
error = gpio_keys_pinctrl_configure(ddata, true);
if (error) {
@@ -928,6 +984,21 @@ static int gpio_keys_resume(struct device *dev)
gpio_keys_report_state(ddata);
return 0;
}
+
+#else
+
+static void gpio_keys_syscore_resume(void){}
+
+static int gpio_keys_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int gpio_keys_resume(struct device *dev)
+{
+ return 0;
+}
+
#endif
static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index d15b33813021..ed1935f300a7 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1232,6 +1232,7 @@ static const struct acpi_device_id elan_acpi_id[] = {
{ "ELAN0000", 0 },
{ "ELAN0100", 0 },
{ "ELAN0600", 0 },
+ { "ELAN0605", 0 },
{ "ELAN1000", 0 },
{ }
};
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 075c18e0e4ae..2d564aabbc74 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -12,7 +12,6 @@ menuconfig INPUT_TOUCHSCREEN
if INPUT_TOUCHSCREEN
source "drivers/input/touchscreen/synaptics_dsx/Kconfig"
-source "drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig"
config OF_TOUCHSCREEN
def_tristate INPUT
@@ -1128,6 +1127,16 @@ config TOUCHSCREEN_FT5X06_GESTURE
If unsure, say N.
+config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
+ bool "Synaptics DSX firmware update extra sysfs attributes"
+ depends on TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE
+ help
+ Say Y here to enable support for extra sysfs attributes
+ supporting firmware update in a development environment.
+ This does not affect the core or other subsystem attributes.
+
+ If unsure, say N.
+
config TOUCHSCREEN_ROHM_BU21023
tristate "ROHM BU21023/24 Dual touch support resistive touchscreens"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 2e0161cf95bc..f5be6fc19751 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -70,7 +70,6 @@ obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21) += synaptics_dsx/
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v26) += synaptics_dsx_2.6/
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
index 0ec16e606545..4787f2bcd768 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
@@ -102,6 +102,7 @@
(fwu->config_data[2] == config_id[2]) && \
(fwu->config_data[3] == config_id[3]))
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
static ssize_t fwu_sysfs_show_image(struct file *data_file,
struct kobject *kobj, struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count);
@@ -157,6 +158,7 @@ static ssize_t fwu_sysfs_config_id_show(struct device *dev,
static ssize_t fwu_sysfs_package_id_show(struct device *dev,
struct device_attribute *attr, char *buf);
+#endif
enum bl_version {
V5 = 5,
@@ -296,6 +298,7 @@ struct synaptics_rmi4_fwu_handle {
struct synaptics_rmi4_data *rmi4_data;
};
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
static struct bin_attribute dev_attr_data = {
.attr = {
.name = "data",
@@ -305,9 +308,11 @@ static struct bin_attribute dev_attr_data = {
.read = fwu_sysfs_show_image,
.write = fwu_sysfs_store_image,
};
+#endif
static struct device_attribute attrs[] = {
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
__ATTR(force_update_fw, S_IWUSR | S_IWGRP,
NULL,
fwu_sysfs_force_reflash_store),
@@ -353,6 +358,7 @@ static struct device_attribute attrs[] = {
__ATTR(package_id, S_IRUGO,
fwu_sysfs_package_id_show,
synaptics_rmi4_store_error),
+#endif
};
static struct synaptics_rmi4_fwu_handle *fwu;
@@ -1220,6 +1226,7 @@ write_config:
return retval;
}
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
static int fwu_start_write_config(void)
{
int retval;
@@ -1395,6 +1402,7 @@ exit:
return retval;
}
+#endif
static int fwu_do_lockdown(void)
{
@@ -1585,6 +1593,7 @@ int synaptics_dsx_fw_updater(unsigned char *fw_data)
}
EXPORT_SYMBOL(synaptics_dsx_fw_updater);
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
static ssize_t fwu_sysfs_show_image(struct file *data_file,
struct kobject *kobj, struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count)
@@ -1972,6 +1981,7 @@ static ssize_t fwu_sysfs_package_id_show(struct device *dev,
(package_id[1] << 8) | package_id[0],
(package_id[3] << 8) | package_id[2]);
}
+#endif
static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
unsigned char intr_mask)
@@ -2045,6 +2055,7 @@ static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
fwu->do_lockdown = DO_LOCKDOWN;
fwu->initialized = true;
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
retval = sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj,
&dev_attr_data);
if (retval < 0) {
@@ -2053,6 +2064,7 @@ static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
__func__);
goto exit_free_fwu;
}
+#endif
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
@@ -2074,7 +2086,9 @@ exit_remove_attrs:
&attrs[attr_count].attr);
}
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+#endif
exit_free_fwu:
kfree(fwu);
@@ -2096,7 +2110,9 @@ static void synaptics_rmi4_fwu_remove(struct synaptics_rmi4_data *rmi4_data)
&attrs[attr_count].attr);
}
+#ifdef CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_EXTRA_SYSFS
sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
+#endif
kfree(fwu->read_config_buf);
kfree(fwu);
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig b/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig
deleted file mode 100644
index 53896288ba77..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig
+++ /dev/null
@@ -1,127 +0,0 @@
-#
-# Synaptics DSX v2.6 touchscreen driver configuration
-#
-menuconfig TOUCHSCREEN_SYNAPTICS_DSX_v26
- bool "Synaptics DSX v2.6 touchscreen"
- default y
- help
- Say Y here if you have a Synaptics DSX touchscreen connected
- to your system.
-
- If unsure, say N.
-
-if TOUCHSCREEN_SYNAPTICS_DSX_v26
-
-choice
- default TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26
- prompt "Synaptics DSX v2.6 bus interface"
-config TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26
- bool "RMI over I2C"
- depends on I2C
-config TOUCHSCREEN_SYNAPTICS_DSX_SPI_v26
- bool "RMI over SPI"
- depends on SPI_MASTER
-config TOUCHSCREEN_SYNAPTICS_DSX_RMI_HID_I2C_v26
- bool "HID over I2C"
- depends on I2C
-endchoice
-
-config TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
- tristate "Synaptics DSX v2.6 core driver module"
- depends on I2C || SPI_MASTER
- help
- Say Y here to enable basic touch reporting functionality.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called synaptics_dsx_core.
-
-config TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v26
- tristate "Synaptics DSX v2.6 RMI device module"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
- help
- Say Y here to enable support for direct RMI register access.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called synaptics_dsx_rmi_dev.
-
-config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v26
- tristate "Synaptics DSX v2.6 firmware update module"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
- help
- Say Y here to enable support for doing firmware update.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called synaptics_dsx_fw_update.
-
-config TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING_v26
- tristate "Synaptics DSX v2.6 test reporting module"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
- help
- Say Y here to enable support for retrieving production test reports.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called synaptics_dsx_test_reporting.
-
-config TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_v26
- tristate "Synaptics DSX v2.6 proximity module"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
- help
- Say Y here to enable support for proximity functionality.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called synaptics_dsx_proximity.
-
-config TOUCHSCREEN_SYNAPTICS_DSX_ACTIVE_PEN_v26
- tristate "Synaptics DSX v2.6 active pen module"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
- help
- Say Y here to enable support for active pen functionality.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called synaptics_dsx_active_pen.
-
-config TOUCHSCREEN_SYNAPTICS_DSX_GESTURE_v26
- tristate "Synaptics DSX v2.6 user defined gesture module"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
- help
- Say Y here to enable support for user defined gesture functionality.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called synaptics_dsx_gesture.
-
-config TOUCHSCREEN_SYNAPTICS_DSX_VIDEO_v26
- tristate "Synaptics DSX v2.6 video module"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
- help
- Say Y here to enable support for video communication functionality.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called synaptics_dsx_video.
-
-config SECURE_TOUCH_SYNAPTICS_DSX_V26
- bool "Secure Touch support for Synaptics V2.6 Touchscreen"
- depends on TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26
- help
- Say Y here
- -Synaptics DSX V2.6 touch driver is connected
- -To enable secure touch for Synaptics DSX V2.6 touch driver
-
- If unsure, say N.
-
-endif
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/Makefile b/drivers/input/touchscreen/synaptics_dsx_2.6/Makefile
deleted file mode 100644
index e5e72153f8c4..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Makefile for the Synaptics DSX touchscreen driver.
-#
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26) += synaptics_dsx_i2c.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_SPI_v26) += synaptics_dsx_spi.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_HID_I2C_v26) += synaptics_dsx_rmi_hid_i2c.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26) += synaptics_dsx_core.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v26) += synaptics_dsx_rmi_dev.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v26) += synaptics_dsx_fw_update.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING_v26) += synaptics_dsx_test_reporting.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_v26) += synaptics_dsx_proximity.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_ACTIVE_PEN_v26) += synaptics_dsx_active_pen.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_GESTURE_v26) += synaptics_dsx_gesture.o
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_VIDEO_v26) += synaptics_dsx_video.o
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_active_pen.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_active_pen.c
deleted file mode 100644
index db5324ab09fe..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_active_pen.c
+++ /dev/null
@@ -1,624 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx_v2_6.h>
-#include "synaptics_dsx_core.h"
-
-#define APEN_PHYS_NAME "synaptics_dsx/active_pen"
-
-#define ACTIVE_PEN_MAX_PRESSURE_16BIT 65535
-#define ACTIVE_PEN_MAX_PRESSURE_8BIT 255
-
-struct synaptics_rmi4_f12_query_8 {
- union {
- struct {
- unsigned char size_of_query9;
- struct {
- unsigned char data0_is_present:1;
- unsigned char data1_is_present:1;
- unsigned char data2_is_present:1;
- unsigned char data3_is_present:1;
- unsigned char data4_is_present:1;
- unsigned char data5_is_present:1;
- unsigned char data6_is_present:1;
- unsigned char data7_is_present:1;
- } __packed;
- };
- unsigned char data[2];
- };
-};
-
-struct apen_data_8b_pressure {
- union {
- struct {
- unsigned char status_pen:1;
- unsigned char status_invert:1;
- unsigned char status_barrel:1;
- unsigned char status_reserved:5;
- unsigned char x_lsb;
- unsigned char x_msb;
- unsigned char y_lsb;
- unsigned char y_msb;
- unsigned char pressure_msb;
- unsigned char battery_state;
- unsigned char pen_id_0_7;
- unsigned char pen_id_8_15;
- unsigned char pen_id_16_23;
- unsigned char pen_id_24_31;
- } __packed;
- unsigned char data[11];
- };
-};
-
-struct apen_data {
- union {
- struct {
- unsigned char status_pen:1;
- unsigned char status_invert:1;
- unsigned char status_barrel:1;
- unsigned char status_reserved:5;
- unsigned char x_lsb;
- unsigned char x_msb;
- unsigned char y_lsb;
- unsigned char y_msb;
- unsigned char pressure_lsb;
- unsigned char pressure_msb;
- unsigned char battery_state;
- unsigned char pen_id_0_7;
- unsigned char pen_id_8_15;
- unsigned char pen_id_16_23;
- unsigned char pen_id_24_31;
- } __packed;
- unsigned char data[12];
- };
-};
-
-struct synaptics_rmi4_apen_handle {
- bool apen_present;
- unsigned char intr_mask;
- unsigned char battery_state;
- unsigned short query_base_addr;
- unsigned short control_base_addr;
- unsigned short data_base_addr;
- unsigned short command_base_addr;
- unsigned short apen_data_addr;
- unsigned short max_pressure;
- unsigned int pen_id;
- struct input_dev *apen_dev;
- struct apen_data *apen_data;
- struct synaptics_rmi4_data *rmi4_data;
-};
-
-static struct synaptics_rmi4_apen_handle *apen;
-
-DECLARE_COMPLETION(apen_remove_complete);
-
-static void apen_lift(void)
-{
- input_report_key(apen->apen_dev, BTN_TOUCH, 0);
- input_report_key(apen->apen_dev, BTN_TOOL_PEN, 0);
- input_report_key(apen->apen_dev, BTN_TOOL_RUBBER, 0);
- input_sync(apen->apen_dev);
- apen->apen_present = false;
-
- return;
-}
-
-static void apen_report(void)
-{
- int retval;
- int x;
- int y;
- int pressure;
- static int invert = -1;
- struct apen_data_8b_pressure *apen_data_8b;
- struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- apen->apen_data_addr,
- apen->apen_data->data,
- sizeof(apen->apen_data->data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read active pen data\n",
- __func__);
- return;
- }
-
- if (apen->apen_data->status_pen == 0) {
- if (apen->apen_present)
- apen_lift();
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: No active pen data\n",
- __func__);
-
- return;
- }
-
- x = (apen->apen_data->x_msb << 8) | (apen->apen_data->x_lsb);
- y = (apen->apen_data->y_msb << 8) | (apen->apen_data->y_lsb);
-
- if ((x == -1) && (y == -1)) {
- if (apen->apen_present)
- apen_lift();
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Active pen in range but no valid x & y\n",
- __func__);
-
- return;
- }
-
- if (!apen->apen_present)
- invert = -1;
-
- if (invert != -1 && invert != apen->apen_data->status_invert)
- apen_lift();
-
- invert = apen->apen_data->status_invert;
-
- if (apen->max_pressure == ACTIVE_PEN_MAX_PRESSURE_16BIT) {
- pressure = (apen->apen_data->pressure_msb << 8) |
- apen->apen_data->pressure_lsb;
- apen->battery_state = apen->apen_data->battery_state;
- apen->pen_id = (apen->apen_data->pen_id_24_31 << 24) |
- (apen->apen_data->pen_id_16_23 << 16) |
- (apen->apen_data->pen_id_8_15 << 8) |
- apen->apen_data->pen_id_0_7;
- } else {
- apen_data_8b = (struct apen_data_8b_pressure *)apen->apen_data;
- pressure = apen_data_8b->pressure_msb;
- apen->battery_state = apen_data_8b->battery_state;
- apen->pen_id = (apen_data_8b->pen_id_24_31 << 24) |
- (apen_data_8b->pen_id_16_23 << 16) |
- (apen_data_8b->pen_id_8_15 << 8) |
- apen_data_8b->pen_id_0_7;
- }
-
- input_report_key(apen->apen_dev, BTN_TOUCH, pressure > 0 ? 1 : 0);
- input_report_key(apen->apen_dev,
- apen->apen_data->status_invert > 0 ?
- BTN_TOOL_RUBBER : BTN_TOOL_PEN, 1);
- input_report_key(apen->apen_dev,
- BTN_STYLUS, apen->apen_data->status_barrel > 0 ?
- 1 : 0);
- input_report_abs(apen->apen_dev, ABS_X, x);
- input_report_abs(apen->apen_dev, ABS_Y, y);
- input_report_abs(apen->apen_dev, ABS_PRESSURE, pressure);
-
- input_sync(apen->apen_dev);
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Active pen: status = %d, invert = %d, barrel = %d, x = %d, y = %d, pressure = %d\n",
- __func__,
- apen->apen_data->status_pen,
- apen->apen_data->status_invert,
- apen->apen_data->status_barrel,
- x, y, pressure);
-
- apen->apen_present = true;
-
- return;
-}
-
-static void apen_set_params(void)
-{
- input_set_abs_params(apen->apen_dev, ABS_X, 0,
- apen->rmi4_data->sensor_max_x, 0, 0);
- input_set_abs_params(apen->apen_dev, ABS_Y, 0,
- apen->rmi4_data->sensor_max_y, 0, 0);
- input_set_abs_params(apen->apen_dev, ABS_PRESSURE, 0,
- apen->max_pressure, 0, 0);
-
- return;
-}
-
-static int apen_pressure(struct synaptics_rmi4_f12_query_8 *query_8)
-{
- int retval;
- unsigned char ii;
- unsigned char data_reg_presence;
- unsigned char size_of_query_9;
- unsigned char *query_9;
- unsigned char *data_desc;
- struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
-
- data_reg_presence = query_8->data[1];
-
- size_of_query_9 = query_8->size_of_query9;
- query_9 = kmalloc(size_of_query_9, GFP_KERNEL);
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- apen->query_base_addr + 9,
- query_9,
- size_of_query_9);
- if (retval < 0)
- goto exit;
-
- data_desc = query_9;
-
- for (ii = 0; ii < 6; ii++) {
- if (!(data_reg_presence & (1 << ii)))
- continue; /* The data register is not present */
- data_desc++; /* Jump over the size entry */
- while (*data_desc & (1 << 7))
- data_desc++;
- data_desc++; /* Go to the next descriptor */
- }
-
- data_desc++; /* Jump over the size entry */
- /* Check for the presence of subpackets 1 and 2 */
- if ((*data_desc & (3 << 1)) == (3 << 1))
- apen->max_pressure = ACTIVE_PEN_MAX_PRESSURE_16BIT;
- else
- apen->max_pressure = ACTIVE_PEN_MAX_PRESSURE_8BIT;
-
-exit:
- kfree(query_9);
-
- return retval;
-}
-
-static int apen_reg_init(void)
-{
- int retval;
- unsigned char data_offset;
- unsigned char size_of_query8;
- struct synaptics_rmi4_f12_query_8 query_8;
- struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- apen->query_base_addr + 7,
- &size_of_query8,
- sizeof(size_of_query8));
- if (retval < 0)
- return retval;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- apen->query_base_addr + 8,
- query_8.data,
- sizeof(query_8.data));
- if (retval < 0)
- return retval;
-
- if ((size_of_query8 >= 2) && (query_8.data6_is_present)) {
- data_offset = query_8.data0_is_present +
- query_8.data1_is_present +
- query_8.data2_is_present +
- query_8.data3_is_present +
- query_8.data4_is_present +
- query_8.data5_is_present;
- apen->apen_data_addr = apen->data_base_addr + data_offset;
- retval = apen_pressure(&query_8);
- if (retval < 0)
- return retval;
- } else {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Active pen support unavailable\n",
- __func__);
- retval = -ENODEV;
- }
-
- return retval;
-}
-
-static int apen_scan_pdt(void)
-{
- int retval;
- unsigned char ii;
- unsigned char page;
- unsigned char intr_count = 0;
- unsigned char intr_off;
- unsigned char intr_src;
- unsigned short addr;
- struct synaptics_rmi4_fn_desc fd;
- struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
-
- for (page = 0; page < PAGES_TO_SERVICE; page++) {
- for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
- addr |= (page << 8);
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- addr,
- (unsigned char *)&fd,
- sizeof(fd));
- if (retval < 0)
- return retval;
-
- addr &= ~(MASK_8BIT << 8);
-
- if (fd.fn_number) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Found F%02x\n",
- __func__, fd.fn_number);
- switch (fd.fn_number) {
- case SYNAPTICS_RMI4_F12:
- goto f12_found;
- break;
- }
- } else {
- break;
- }
-
- intr_count += fd.intr_src_count;
- }
- }
-
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to find F12\n",
- __func__);
- return -EINVAL;
-
-f12_found:
- apen->query_base_addr = fd.query_base_addr | (page << 8);
- apen->control_base_addr = fd.ctrl_base_addr | (page << 8);
- apen->data_base_addr = fd.data_base_addr | (page << 8);
- apen->command_base_addr = fd.cmd_base_addr | (page << 8);
-
- retval = apen_reg_init();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to initialize active pen registers\n",
- __func__);
- return retval;
- }
-
- apen->intr_mask = 0;
- intr_src = fd.intr_src_count;
- intr_off = intr_count % 8;
- for (ii = intr_off;
- ii < (intr_src + intr_off);
- ii++) {
- apen->intr_mask |= 1 << ii;
- }
-
- rmi4_data->intr_mask[0] |= apen->intr_mask;
-
- addr = rmi4_data->f01_ctrl_base_addr + 1;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- addr,
- &(rmi4_data->intr_mask[0]),
- sizeof(rmi4_data->intr_mask[0]));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set interrupt enable bit\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static void synaptics_rmi4_apen_attn(struct synaptics_rmi4_data *rmi4_data,
- unsigned char intr_mask)
-{
- if (!apen)
- return;
-
- if (apen->intr_mask & intr_mask)
- apen_report();
-
- return;
-}
-
-static int synaptics_rmi4_apen_init(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
-
- if (apen) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Handle already exists\n",
- __func__);
- return 0;
- }
-
- apen = kzalloc(sizeof(*apen), GFP_KERNEL);
- if (!apen) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for apen\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- apen->apen_data = kzalloc(sizeof(*(apen->apen_data)), GFP_KERNEL);
- if (!apen->apen_data) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for apen_data\n",
- __func__);
- retval = -ENOMEM;
- goto exit_free_apen;
- }
-
- apen->rmi4_data = rmi4_data;
-
- retval = apen_scan_pdt();
- if (retval < 0)
- goto exit_free_apen_data;
-
- apen->apen_dev = input_allocate_device();
- if (apen->apen_dev == NULL) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to allocate active pen device\n",
- __func__);
- retval = -ENOMEM;
- goto exit_free_apen_data;
- }
-
- apen->apen_dev->name = ACTIVE_PEN_DRIVER_NAME;
- apen->apen_dev->phys = APEN_PHYS_NAME;
- apen->apen_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
- apen->apen_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
- apen->apen_dev->dev.parent = rmi4_data->pdev->dev.parent;
- input_set_drvdata(apen->apen_dev, rmi4_data);
-
- set_bit(EV_KEY, apen->apen_dev->evbit);
- set_bit(EV_ABS, apen->apen_dev->evbit);
- set_bit(BTN_TOUCH, apen->apen_dev->keybit);
- set_bit(BTN_TOOL_PEN, apen->apen_dev->keybit);
- set_bit(BTN_TOOL_RUBBER, apen->apen_dev->keybit);
- set_bit(BTN_STYLUS, apen->apen_dev->keybit);
-#ifdef INPUT_PROP_DIRECT
- set_bit(INPUT_PROP_DIRECT, apen->apen_dev->propbit);
-#endif
-
- apen_set_params();
-
- retval = input_register_device(apen->apen_dev);
- if (retval) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to register active pen device\n",
- __func__);
- goto exit_free_input_device;
- }
-
- return 0;
-
-exit_free_input_device:
- input_free_device(apen->apen_dev);
-
-exit_free_apen_data:
- kfree(apen->apen_data);
-
-exit_free_apen:
- kfree(apen);
- apen = NULL;
-
-exit:
- return retval;
-}
-
-static void synaptics_rmi4_apen_remove(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!apen)
- goto exit;
-
- input_unregister_device(apen->apen_dev);
- kfree(apen->apen_data);
- kfree(apen);
- apen = NULL;
-
-exit:
- complete(&apen_remove_complete);
-
- return;
-}
-
-static void synaptics_rmi4_apen_reset(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!apen) {
- synaptics_rmi4_apen_init(rmi4_data);
- return;
- }
-
- apen_lift();
-
- apen_scan_pdt();
-
- return;
-}
-
-static void synaptics_rmi4_apen_reinit(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!apen)
- return;
-
- apen_lift();
-
- return;
-}
-
-static void synaptics_rmi4_apen_e_suspend(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!apen)
- return;
-
- apen_lift();
-
- return;
-}
-
-static void synaptics_rmi4_apen_suspend(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!apen)
- return;
-
- apen_lift();
-
- return;
-}
-
-static struct synaptics_rmi4_exp_fn active_pen_module = {
- .fn_type = RMI_ACTIVE_PEN,
- .init = synaptics_rmi4_apen_init,
- .remove = synaptics_rmi4_apen_remove,
- .reset = synaptics_rmi4_apen_reset,
- .reinit = synaptics_rmi4_apen_reinit,
- .early_suspend = synaptics_rmi4_apen_e_suspend,
- .suspend = synaptics_rmi4_apen_suspend,
- .resume = NULL,
- .late_resume = NULL,
- .attn = synaptics_rmi4_apen_attn,
-};
-
-static int __init rmi4_active_pen_module_init(void)
-{
- synaptics_rmi4_new_function(&active_pen_module, true);
-
- return 0;
-}
-
-static void __exit rmi4_active_pen_module_exit(void)
-{
- synaptics_rmi4_new_function(&active_pen_module, false);
-
- wait_for_completion(&apen_remove_complete);
-
- return;
-}
-
-module_init(rmi4_active_pen_module_init);
-module_exit(rmi4_active_pen_module_exit);
-
-MODULE_AUTHOR("Synaptics, Inc.");
-MODULE_DESCRIPTION("Synaptics DSX Active Pen Module");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
deleted file mode 100644
index d358f329e7a8..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c
+++ /dev/null
@@ -1,4711 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-#include <linux/input/synaptics_dsx_v2_6.h>
-#include "synaptics_dsx_core.h"
-#ifdef KERNEL_ABOVE_2_6_38
-#include <linux/input/mt.h>
-#endif
-
-#define INPUT_PHYS_NAME "synaptics_dsx/touch_input"
-#define STYLUS_PHYS_NAME "synaptics_dsx/stylus"
-
-#define VIRTUAL_KEY_MAP_FILE_NAME "virtualkeys." PLATFORM_DRIVER_NAME
-
-#ifdef KERNEL_ABOVE_2_6_38
-#define TYPE_B_PROTOCOL
-#endif
-
-#define WAKEUP_GESTURE false
-
-#define NO_0D_WHILE_2D
-#define REPORT_2D_Z
-#define REPORT_2D_W
-/*
-#define REPORT_2D_PRESSURE
-*/
-
-#define F12_DATA_15_WORKAROUND
-
-#define IGNORE_FN_INIT_FAILURE
-
-#define FB_READY_RESET
-#define FB_READY_WAIT_MS 100
-#define FB_READY_TIMEOUT_S 30
-
-#define RPT_TYPE (1 << 0)
-#define RPT_X_LSB (1 << 1)
-#define RPT_X_MSB (1 << 2)
-#define RPT_Y_LSB (1 << 3)
-#define RPT_Y_MSB (1 << 4)
-#define RPT_Z (1 << 5)
-#define RPT_WX (1 << 6)
-#define RPT_WY (1 << 7)
-#define RPT_DEFAULT (RPT_TYPE | RPT_X_LSB | RPT_X_MSB | RPT_Y_LSB | RPT_Y_MSB)
-
-#define REBUILD_WORK_DELAY_MS 500 /* ms */
-
-#define EXP_FN_WORK_DELAY_MS 500 /* ms */
-#define MAX_F11_TOUCH_WIDTH 15
-#define MAX_F12_TOUCH_WIDTH 255
-#define MAX_F12_TOUCH_PRESSURE 255
-
-#define CHECK_STATUS_TIMEOUT_MS 100
-
-#define F01_STD_QUERY_LEN 21
-#define F01_BUID_ID_OFFSET 18
-
-#define STATUS_NO_ERROR 0x00
-#define STATUS_RESET_OCCURRED 0x01
-#define STATUS_INVALID_CONFIG 0x02
-#define STATUS_DEVICE_FAILURE 0x03
-#define STATUS_CONFIG_CRC_FAILURE 0x04
-#define STATUS_FIRMWARE_CRC_FAILURE 0x05
-#define STATUS_CRC_IN_PROGRESS 0x06
-
-#define NORMAL_OPERATION (0 << 0)
-#define SENSOR_SLEEP (1 << 0)
-#define NO_SLEEP_OFF (0 << 2)
-#define NO_SLEEP_ON (1 << 2)
-#define CONFIGURED (1 << 7)
-
-#define F11_CONTINUOUS_MODE 0x00
-#define F11_WAKEUP_GESTURE_MODE 0x04
-#define F12_CONTINUOUS_MODE 0x00
-#define F12_WAKEUP_GESTURE_MODE 0x02
-#define F12_UDG_DETECT 0x0f
-
-static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data,
- bool *was_in_bl_mode);
-static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data);
-static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data,
- bool rebuild);
-
-#ifdef CONFIG_FB
-static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work);
-static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self,
- unsigned long event, void *data);
-#endif
-
-#ifdef CONFIG_HAS_EARLYSUSPEND
-#ifndef CONFIG_FB
-#define USE_EARLYSUSPEND
-#endif
-#endif
-
-#ifdef USE_EARLYSUSPEND
-static void synaptics_rmi4_early_suspend(struct early_suspend *h);
-
-static void synaptics_rmi4_late_resume(struct early_suspend *h);
-#endif
-
-static int synaptics_rmi4_suspend(struct device *dev);
-
-static int synaptics_rmi4_resume(struct device *dev);
-
-static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t synaptics_rmi4_suspend_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t synaptics_rmi4_wake_gesture_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf);
-
-#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
-static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-#endif
-
-static irqreturn_t synaptics_rmi4_irq(int irq, void *data);
-
-struct synaptics_rmi4_f01_device_status {
- union {
- struct {
- unsigned char status_code:4;
- unsigned char reserved:2;
- unsigned char flash_prog:1;
- unsigned char unconfigured:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct synaptics_rmi4_f11_query_0_5 {
- union {
- struct {
- /* query 0 */
- unsigned char f11_query0_b0__2:3;
- unsigned char has_query_9:1;
- unsigned char has_query_11:1;
- unsigned char has_query_12:1;
- unsigned char has_query_27:1;
- unsigned char has_query_28:1;
-
- /* query 1 */
- unsigned char num_of_fingers:3;
- unsigned char has_rel:1;
- unsigned char has_abs:1;
- unsigned char has_gestures:1;
- unsigned char has_sensitibity_adjust:1;
- unsigned char f11_query1_b7:1;
-
- /* query 2 */
- unsigned char num_of_x_electrodes;
-
- /* query 3 */
- unsigned char num_of_y_electrodes;
-
- /* query 4 */
- unsigned char max_electrodes:7;
- unsigned char f11_query4_b7:1;
-
- /* query 5 */
- unsigned char abs_data_size:2;
- unsigned char has_anchored_finger:1;
- unsigned char has_adj_hyst:1;
- unsigned char has_dribble:1;
- unsigned char has_bending_correction:1;
- unsigned char has_large_object_suppression:1;
- unsigned char has_jitter_filter:1;
- } __packed;
- unsigned char data[6];
- };
-};
-
-struct synaptics_rmi4_f11_query_7_8 {
- union {
- struct {
- /* query 7 */
- unsigned char has_single_tap:1;
- unsigned char has_tap_and_hold:1;
- unsigned char has_double_tap:1;
- unsigned char has_early_tap:1;
- unsigned char has_flick:1;
- unsigned char has_press:1;
- unsigned char has_pinch:1;
- unsigned char has_chiral_scroll:1;
-
- /* query 8 */
- unsigned char has_palm_detect:1;
- unsigned char has_rotate:1;
- unsigned char has_touch_shapes:1;
- unsigned char has_scroll_zones:1;
- unsigned char individual_scroll_zones:1;
- unsigned char has_multi_finger_scroll:1;
- unsigned char has_multi_finger_scroll_edge_motion:1;
- unsigned char has_multi_finger_scroll_inertia:1;
- } __packed;
- unsigned char data[2];
- };
-};
-
-struct synaptics_rmi4_f11_query_9 {
- union {
- struct {
- unsigned char has_pen:1;
- unsigned char has_proximity:1;
- unsigned char has_large_object_sensitivity:1;
- unsigned char has_suppress_on_large_object_detect:1;
- unsigned char has_two_pen_thresholds:1;
- unsigned char has_contact_geometry:1;
- unsigned char has_pen_hover_discrimination:1;
- unsigned char has_pen_hover_and_edge_filters:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct synaptics_rmi4_f11_query_12 {
- union {
- struct {
- unsigned char has_small_object_detection:1;
- unsigned char has_small_object_detection_tuning:1;
- unsigned char has_8bit_w:1;
- unsigned char has_2d_adjustable_mapping:1;
- unsigned char has_general_information_2:1;
- unsigned char has_physical_properties:1;
- unsigned char has_finger_limit:1;
- unsigned char has_linear_cofficient_2:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct synaptics_rmi4_f11_query_27 {
- union {
- struct {
- unsigned char f11_query27_b0:1;
- unsigned char has_pen_position_correction:1;
- unsigned char has_pen_jitter_filter_coefficient:1;
- unsigned char has_group_decomposition:1;
- unsigned char has_wakeup_gesture:1;
- unsigned char has_small_finger_correction:1;
- unsigned char has_data_37:1;
- unsigned char f11_query27_b7:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct synaptics_rmi4_f11_ctrl_6_9 {
- union {
- struct {
- unsigned char sensor_max_x_pos_7_0;
- unsigned char sensor_max_x_pos_11_8:4;
- unsigned char f11_ctrl7_b4__7:4;
- unsigned char sensor_max_y_pos_7_0;
- unsigned char sensor_max_y_pos_11_8:4;
- unsigned char f11_ctrl9_b4__7:4;
- } __packed;
- unsigned char data[4];
- };
-};
-
-struct synaptics_rmi4_f11_data_1_5 {
- union {
- struct {
- unsigned char x_position_11_4;
- unsigned char y_position_11_4;
- unsigned char x_position_3_0:4;
- unsigned char y_position_3_0:4;
- unsigned char wx:4;
- unsigned char wy:4;
- unsigned char z;
- } __packed;
- unsigned char data[5];
- };
-};
-
-struct synaptics_rmi4_f12_query_5 {
- union {
- struct {
- unsigned char size_of_query6;
- struct {
- unsigned char ctrl0_is_present:1;
- unsigned char ctrl1_is_present:1;
- unsigned char ctrl2_is_present:1;
- unsigned char ctrl3_is_present:1;
- unsigned char ctrl4_is_present:1;
- unsigned char ctrl5_is_present:1;
- unsigned char ctrl6_is_present:1;
- unsigned char ctrl7_is_present:1;
- } __packed;
- struct {
- unsigned char ctrl8_is_present:1;
- unsigned char ctrl9_is_present:1;
- unsigned char ctrl10_is_present:1;
- unsigned char ctrl11_is_present:1;
- unsigned char ctrl12_is_present:1;
- unsigned char ctrl13_is_present:1;
- unsigned char ctrl14_is_present:1;
- unsigned char ctrl15_is_present:1;
- } __packed;
- struct {
- unsigned char ctrl16_is_present:1;
- unsigned char ctrl17_is_present:1;
- unsigned char ctrl18_is_present:1;
- unsigned char ctrl19_is_present:1;
- unsigned char ctrl20_is_present:1;
- unsigned char ctrl21_is_present:1;
- unsigned char ctrl22_is_present:1;
- unsigned char ctrl23_is_present:1;
- } __packed;
- struct {
- unsigned char ctrl24_is_present:1;
- unsigned char ctrl25_is_present:1;
- unsigned char ctrl26_is_present:1;
- unsigned char ctrl27_is_present:1;
- unsigned char ctrl28_is_present:1;
- unsigned char ctrl29_is_present:1;
- unsigned char ctrl30_is_present:1;
- unsigned char ctrl31_is_present:1;
- } __packed;
- };
- unsigned char data[5];
- };
-};
-
-struct synaptics_rmi4_f12_query_8 {
- union {
- struct {
- unsigned char size_of_query9;
- struct {
- unsigned char data0_is_present:1;
- unsigned char data1_is_present:1;
- unsigned char data2_is_present:1;
- unsigned char data3_is_present:1;
- unsigned char data4_is_present:1;
- unsigned char data5_is_present:1;
- unsigned char data6_is_present:1;
- unsigned char data7_is_present:1;
- } __packed;
- struct {
- unsigned char data8_is_present:1;
- unsigned char data9_is_present:1;
- unsigned char data10_is_present:1;
- unsigned char data11_is_present:1;
- unsigned char data12_is_present:1;
- unsigned char data13_is_present:1;
- unsigned char data14_is_present:1;
- unsigned char data15_is_present:1;
- } __packed;
- struct {
- unsigned char data16_is_present:1;
- unsigned char data17_is_present:1;
- unsigned char data18_is_present:1;
- unsigned char data19_is_present:1;
- unsigned char data20_is_present:1;
- unsigned char data21_is_present:1;
- unsigned char data22_is_present:1;
- unsigned char data23_is_present:1;
- } __packed;
- };
- unsigned char data[4];
- };
-};
-
-struct synaptics_rmi4_f12_ctrl_8 {
- union {
- struct {
- unsigned char max_x_coord_lsb;
- unsigned char max_x_coord_msb;
- unsigned char max_y_coord_lsb;
- unsigned char max_y_coord_msb;
- unsigned char rx_pitch_lsb;
- unsigned char rx_pitch_msb;
- unsigned char tx_pitch_lsb;
- unsigned char tx_pitch_msb;
- unsigned char low_rx_clip;
- unsigned char high_rx_clip;
- unsigned char low_tx_clip;
- unsigned char high_tx_clip;
- unsigned char num_of_rx;
- unsigned char num_of_tx;
- };
- unsigned char data[14];
- };
-};
-
-struct synaptics_rmi4_f12_ctrl_23 {
- union {
- struct {
- unsigned char finger_enable:1;
- unsigned char active_stylus_enable:1;
- unsigned char palm_enable:1;
- unsigned char unclassified_object_enable:1;
- unsigned char hovering_finger_enable:1;
- unsigned char gloved_finger_enable:1;
- unsigned char f12_ctr23_00_b6__7:2;
- unsigned char max_reported_objects;
- unsigned char f12_ctr23_02_b0:1;
- unsigned char report_active_stylus_as_finger:1;
- unsigned char report_palm_as_finger:1;
- unsigned char report_unclassified_object_as_finger:1;
- unsigned char report_hovering_finger_as_finger:1;
- unsigned char report_gloved_finger_as_finger:1;
- unsigned char report_narrow_object_swipe_as_finger:1;
- unsigned char report_handedge_as_finger:1;
- unsigned char cover_enable:1;
- unsigned char stylus_enable:1;
- unsigned char eraser_enable:1;
- unsigned char small_object_enable:1;
- unsigned char f12_ctr23_03_b4__7:4;
- unsigned char report_cover_as_finger:1;
- unsigned char report_stylus_as_finger:1;
- unsigned char report_eraser_as_finger:1;
- unsigned char report_small_object_as_finger:1;
- unsigned char f12_ctr23_04_b4__7:4;
- };
- unsigned char data[5];
- };
-};
-
-struct synaptics_rmi4_f12_ctrl_31 {
- union {
- struct {
- unsigned char max_x_coord_lsb;
- unsigned char max_x_coord_msb;
- unsigned char max_y_coord_lsb;
- unsigned char max_y_coord_msb;
- unsigned char rx_pitch_lsb;
- unsigned char rx_pitch_msb;
- unsigned char rx_clip_low;
- unsigned char rx_clip_high;
- unsigned char wedge_clip_low;
- unsigned char wedge_clip_high;
- unsigned char num_of_p;
- unsigned char num_of_q;
- };
- unsigned char data[12];
- };
-};
-
-struct synaptics_rmi4_f12_finger_data {
- unsigned char object_type_and_status;
- unsigned char x_lsb;
- unsigned char x_msb;
- unsigned char y_lsb;
- unsigned char y_msb;
-#ifdef REPORT_2D_Z
- unsigned char z;
-#endif
-#ifdef REPORT_2D_W
- unsigned char wx;
- unsigned char wy;
-#endif
-};
-
-struct synaptics_rmi4_f1a_query {
- union {
- struct {
- unsigned char max_button_count:3;
- unsigned char f1a_query0_b3__4:2;
- unsigned char has_query4:1;
- unsigned char has_query3:1;
- unsigned char has_query2:1;
- unsigned char has_general_control:1;
- unsigned char has_interrupt_enable:1;
- unsigned char has_multibutton_select:1;
- unsigned char has_tx_rx_map:1;
- unsigned char has_perbutton_threshold:1;
- unsigned char has_release_threshold:1;
- unsigned char has_strongestbtn_hysteresis:1;
- unsigned char has_filter_strength:1;
- } __packed;
- unsigned char data[2];
- };
-};
-
-struct synaptics_rmi4_f1a_query_4 {
- union {
- struct {
- unsigned char has_ctrl19:1;
- unsigned char f1a_query4_b1__4:4;
- unsigned char has_ctrl24:1;
- unsigned char f1a_query4_b6__7:2;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct synaptics_rmi4_f1a_control_0 {
- union {
- struct {
- unsigned char multibutton_report:2;
- unsigned char filter_mode:2;
- unsigned char reserved:4;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct synaptics_rmi4_f1a_control {
- struct synaptics_rmi4_f1a_control_0 general_control;
- unsigned char button_int_enable;
- unsigned char multi_button;
- unsigned char *txrx_map;
- unsigned char *button_threshold;
- unsigned char button_release_threshold;
- unsigned char strongest_button_hysteresis;
- unsigned char filter_strength;
-};
-
-struct synaptics_rmi4_f1a_handle {
- int button_bitmask_size;
- unsigned char max_count;
- unsigned char valid_button_count;
- unsigned char *button_data_buffer;
- unsigned char *button_map;
- struct synaptics_rmi4_f1a_query button_query;
- struct synaptics_rmi4_f1a_control button_control;
-};
-
-struct synaptics_rmi4_exp_fhandler {
- struct synaptics_rmi4_exp_fn *exp_fn;
- bool insert;
- bool remove;
- struct list_head link;
-};
-
-struct synaptics_rmi4_exp_fn_data {
- bool initialized;
- bool queue_work;
- struct mutex mutex;
- struct list_head list;
- struct delayed_work work;
- struct workqueue_struct *workqueue;
- struct synaptics_rmi4_data *rmi4_data;
-};
-
-static struct synaptics_rmi4_exp_fn_data exp_data;
-
-static struct synaptics_dsx_button_map *vir_button_map;
-
-static struct device_attribute attrs[] = {
- __ATTR(reset, S_IWUSR | S_IWGRP,
- NULL,
- synaptics_rmi4_f01_reset_store),
- __ATTR(productinfo, S_IRUGO,
- synaptics_rmi4_f01_productinfo_show,
- NULL),
- __ATTR(buildid, S_IRUGO,
- synaptics_rmi4_f01_buildid_show,
- NULL),
- __ATTR(flashprog, S_IRUGO,
- synaptics_rmi4_f01_flashprog_show,
- NULL),
- __ATTR(0dbutton, (S_IRUGO | S_IWUSR | S_IWGRP),
- synaptics_rmi4_0dbutton_show,
- synaptics_rmi4_0dbutton_store),
- __ATTR(suspend, S_IWUSR | S_IWGRP,
- NULL,
- synaptics_rmi4_suspend_store),
- __ATTR(wake_gesture, (S_IRUGO | S_IWUSR | S_IWGRP),
- synaptics_rmi4_wake_gesture_show,
- synaptics_rmi4_wake_gesture_store),
-#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
- __ATTR(secure_touch_enable, (S_IRUGO | S_IWUSR | S_IWGRP),
- synaptics_rmi4_secure_touch_enable_show,
- synaptics_rmi4_secure_touch_enable_store),
- __ATTR(secure_touch, S_IRUGO,
- synaptics_rmi4_secure_touch_show,
- NULL),
-#endif
-};
-
-static struct kobj_attribute virtual_key_map_attr = {
- .attr = {
- .name = VIRTUAL_KEY_MAP_FILE_NAME,
- .mode = S_IRUGO,
- },
- .show = synaptics_rmi4_virtual_key_map_show,
-};
-
-#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
-static void synaptics_secure_touch_init(struct synaptics_rmi4_data *data)
-{
- data->st_initialized = 0;
- init_completion(&data->st_powerdown);
- init_completion(&data->st_irq_processed);
-
- /* Get clocks */
- data->core_clk = devm_clk_get(data->pdev->dev.parent, "core_clk");
- if (IS_ERR(data->core_clk)) {
- dev_warn(data->pdev->dev.parent,
- "%s: error on clk_get(core_clk): %ld\n", __func__,
- PTR_ERR(data->core_clk));
- data->core_clk = NULL;
- }
-
- data->iface_clk = devm_clk_get(data->pdev->dev.parent, "iface_clk");
- if (IS_ERR(data->iface_clk)) {
- dev_warn(data->pdev->dev.parent,
- "%s: error on clk_get(iface_clk): %ld\n", __func__,
- PTR_ERR(data->iface_clk));
- data->iface_clk = NULL;
- }
-
- data->st_initialized = 1;
-}
-
-static void synaptics_secure_touch_notify(struct synaptics_rmi4_data *rmi4_data)
-{
- sysfs_notify(&rmi4_data->input_dev->dev.kobj, NULL, "secure_touch");
-}
-
-static irqreturn_t synaptics_filter_interrupt(
- struct synaptics_rmi4_data *rmi4_data)
-{
- if (atomic_read(&rmi4_data->st_enabled)) {
- if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 0, 1) == 0) {
- reinit_completion(&rmi4_data->st_irq_processed);
- synaptics_secure_touch_notify(rmi4_data);
- wait_for_completion_interruptible(
- &rmi4_data->st_irq_processed);
- }
- return IRQ_HANDLED;
- }
- return IRQ_NONE;
-}
-
-/*
- * 'blocking' variable will have value 'true' when we want to prevent the driver
- * from accessing the xPU/SMMU protected HW resources while the session is
- * active.
- */
-static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data,
- bool blocking)
-{
- if (atomic_read(&rmi4_data->st_enabled)) {
- atomic_set(&rmi4_data->st_pending_irqs, -1);
- synaptics_secure_touch_notify(rmi4_data);
- if (blocking)
- wait_for_completion_interruptible(
- &rmi4_data->st_powerdown);
- }
-}
-
-#else
-static void synaptics_secure_touch_init(struct synaptics_rmi4_data *rmi4_data)
-{
-}
-
-static irqreturn_t synaptics_filter_interrupt(
- struct synaptics_rmi4_data *rmi4_data)
-{
- return IRQ_NONE;
-}
-
-static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data,
- bool blocking)
-{
-}
-#endif
-
-#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
-static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
-
- return scnprintf(buf, PAGE_SIZE, "%d",
- atomic_read(&rmi4_data->st_enabled));
-}
-/*
- * Accept only "0" and "1" valid values.
- * "0" will reset the st_enabled flag, then wake up the reading process and
- * the interrupt handler.
- * The bus driver is notified via pm_runtime that it is not required to stay
- * awake anymore.
- * It will also make sure the queue of events is emptied in the controller,
- * in case a touch happened in between the secure touch being disabled and
- * the local ISR being ungated.
- * "1" will set the st_enabled flag and clear the st_pending_irqs flag.
- * The bus driver is requested via pm_runtime to stay awake.
- */
-static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- unsigned long value;
- int err = 0;
-
- if (count > 2)
- return -EINVAL;
-
- err = kstrtoul(buf, 10, &value);
- if (err != 0)
- return err;
-
- if (!rmi4_data->st_initialized)
- return -EIO;
-
- err = count;
-
- switch (value) {
- case 0:
- if (atomic_read(&rmi4_data->st_enabled) == 0)
- break;
-
- synaptics_rmi4_bus_put(rmi4_data);
- atomic_set(&rmi4_data->st_enabled, 0);
- synaptics_secure_touch_notify(rmi4_data);
- complete(&rmi4_data->st_irq_processed);
- synaptics_rmi4_irq(rmi4_data->irq, rmi4_data);
- complete(&rmi4_data->st_powerdown);
-
- break;
- case 1:
- if (atomic_read(&rmi4_data->st_enabled)) {
- err = -EBUSY;
- break;
- }
-
- synchronize_irq(rmi4_data->irq);
-
- if (synaptics_rmi4_bus_get(rmi4_data) < 0) {
- dev_err(
- rmi4_data->pdev->dev.parent,
- "synaptics_rmi4_bus_get failed\n");
- err = -EIO;
- break;
- }
- reinit_completion(&rmi4_data->st_powerdown);
- reinit_completion(&rmi4_data->st_irq_processed);
- atomic_set(&rmi4_data->st_enabled, 1);
- atomic_set(&rmi4_data->st_pending_irqs, 0);
- break;
- default:
- dev_err(
- rmi4_data->pdev->dev.parent,
- "unsupported value: %lu\n", value);
- err = -EINVAL;
- break;
- }
- return err;
-}
-
-/*
- * This function returns whether there are pending interrupts, or
- * other error conditions that need to be signaled to the userspace library,
- * according tot he following logic:
- * - st_enabled is 0 if secure touch is not enabled, returning -EBADF
- * - st_pending_irqs is -1 to signal that secure touch is in being stopped,
- * returning -EINVAL
- * - st_pending_irqs is 1 to signal that there is a pending irq, returning
- * the value "1" to the sysfs read operation
- * - st_pending_irqs is 0 (only remaining case left) if the pending interrupt
- * has been processed, so the interrupt handler can be allowed to continue.
- */
-static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- int val = 0;
-
- if (atomic_read(&rmi4_data->st_enabled) == 0)
- return -EBADF;
-
- if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, -1, 0) == -1)
- return -EINVAL;
-
- if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 1, 0) == 1)
- val = 1;
- else
- complete(&rmi4_data->st_irq_processed);
-
- return scnprintf(buf, PAGE_SIZE, "%u", val);
-
-}
-#endif
-
-static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned int reset;
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
-
- if (sscanf(buf, "%u", &reset) != 1)
- return -EINVAL;
-
- if (reset != 1)
- return -EINVAL;
-
- retval = synaptics_rmi4_reset_device(rmi4_data, false);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to issue reset command, error = %d\n",
- __func__, retval);
- return retval;
- }
-
- return count;
-}
-
-static ssize_t synaptics_rmi4_f01_productinfo_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
-
- return snprintf(buf, PAGE_SIZE, "0x%02x 0x%02x\n",
- (rmi4_data->rmi4_mod_info.product_info[0]),
- (rmi4_data->rmi4_mod_info.product_info[1]));
-}
-
-static ssize_t synaptics_rmi4_f01_buildid_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
-
- return snprintf(buf, PAGE_SIZE, "%u\n",
- rmi4_data->firmware_id);
-}
-
-static ssize_t synaptics_rmi4_f01_flashprog_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int retval;
- struct synaptics_rmi4_f01_device_status device_status;
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_data_base_addr,
- device_status.data,
- sizeof(device_status.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read device status, error = %d\n",
- __func__, retval);
- return retval;
- }
-
- return snprintf(buf, PAGE_SIZE, "%u\n",
- device_status.flash_prog);
-}
-
-static ssize_t synaptics_rmi4_0dbutton_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
-
- return snprintf(buf, PAGE_SIZE, "%u\n",
- rmi4_data->button_0d_enabled);
-}
-
-static ssize_t synaptics_rmi4_0dbutton_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned int input;
- unsigned char ii;
- unsigned char intr_enable;
- struct synaptics_rmi4_fn *fhandler;
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- struct synaptics_rmi4_device_info *rmi;
-
- rmi = &(rmi4_data->rmi4_mod_info);
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- input = input > 0 ? 1 : 0;
-
- if (rmi4_data->button_0d_enabled == input)
- return count;
-
- if (list_empty(&rmi->support_fn_list))
- return -ENODEV;
-
- list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) {
- ii = fhandler->intr_reg_num;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_ctrl_base_addr + 1 + ii,
- &intr_enable,
- sizeof(intr_enable));
- if (retval < 0)
- return retval;
-
- if (input == 1)
- intr_enable |= fhandler->intr_mask;
- else
- intr_enable &= ~fhandler->intr_mask;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- rmi4_data->f01_ctrl_base_addr + 1 + ii,
- &intr_enable,
- sizeof(intr_enable));
- if (retval < 0)
- return retval;
- }
- }
-
- rmi4_data->button_0d_enabled = input;
-
- return count;
-}
-
-static ssize_t synaptics_rmi4_suspend_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- unsigned int input;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- if (input == 1)
- synaptics_rmi4_suspend(dev);
- else if (input == 0)
- synaptics_rmi4_resume(dev);
- else
- return -EINVAL;
-
- return count;
-}
-
-static ssize_t synaptics_rmi4_wake_gesture_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
-
- return snprintf(buf, PAGE_SIZE, "%u\n",
- rmi4_data->enable_wakeup_gesture);
-}
-
-static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- input = input > 0 ? 1 : 0;
-
- if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture)
- rmi4_data->enable_wakeup_gesture = input;
-
- return count;
-}
-
-static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj,
- struct kobj_attribute *attr, char *buf)
-{
- int ii;
- int cnt;
- int count = 0;
-
- for (ii = 0; ii < vir_button_map->nbuttons; ii++) {
- cnt = snprintf(buf, PAGE_SIZE - count, "0x01:%d:%d:%d:%d:%d\n",
- vir_button_map->map[ii * 5 + 0],
- vir_button_map->map[ii * 5 + 1],
- vir_button_map->map[ii * 5 + 2],
- vir_button_map->map[ii * 5 + 3],
- vir_button_map->map[ii * 5 + 4]);
- buf += cnt;
- count += cnt;
- }
-
- return count;
-}
-
-static int synaptics_rmi4_f11_abs_report(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn *fhandler)
-{
- int retval;
- unsigned char touch_count = 0; /* number of touch points */
- unsigned char reg_index;
- unsigned char finger;
- unsigned char fingers_supported;
- unsigned char num_of_finger_status_regs;
- unsigned char finger_shift;
- unsigned char finger_status;
- unsigned char finger_status_reg[3];
- unsigned char detected_gestures;
- unsigned short data_addr;
- unsigned short data_offset;
- int x;
- int y;
- int wx;
- int wy;
- int temp;
- struct synaptics_rmi4_f11_data_1_5 data;
- struct synaptics_rmi4_f11_extra_data *extra_data;
-
- /*
- * The number of finger status registers is determined by the
- * maximum number of fingers supported - 2 bits per finger. So
- * the number of finger status registers to read is:
- * register_count = ceil(max_num_of_fingers / 4)
- */
- fingers_supported = fhandler->num_of_data_points;
- num_of_finger_status_regs = (fingers_supported + 3) / 4;
- data_addr = fhandler->full_addr.data_base;
-
- extra_data = (struct synaptics_rmi4_f11_extra_data *)fhandler->extra;
-
- if (rmi4_data->suspend && rmi4_data->enable_wakeup_gesture) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- data_addr + extra_data->data38_offset,
- &detected_gestures,
- sizeof(detected_gestures));
- if (retval < 0)
- return 0;
-
- if (detected_gestures) {
- input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 1);
- input_sync(rmi4_data->input_dev);
- input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 0);
- input_sync(rmi4_data->input_dev);
- rmi4_data->suspend = false;
- }
-
- return 0;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- data_addr,
- finger_status_reg,
- num_of_finger_status_regs);
- if (retval < 0)
- return 0;
-
- mutex_lock(&(rmi4_data->rmi4_report_mutex));
-
- for (finger = 0; finger < fingers_supported; finger++) {
- reg_index = finger / 4;
- finger_shift = (finger % 4) * 2;
- finger_status = (finger_status_reg[reg_index] >> finger_shift)
- & MASK_2BIT;
-
- /*
- * Each 2-bit finger status field represents the following:
- * 00 = finger not present
- * 01 = finger present and data accurate
- * 10 = finger present but data may be inaccurate
- * 11 = reserved
- */
-#ifdef TYPE_B_PROTOCOL
- input_mt_slot(rmi4_data->input_dev, finger);
- input_mt_report_slot_state(rmi4_data->input_dev,
- MT_TOOL_FINGER, finger_status);
-#endif
-
- if (finger_status) {
- data_offset = data_addr +
- num_of_finger_status_regs +
- (finger * sizeof(data.data));
- retval = synaptics_rmi4_reg_read(rmi4_data,
- data_offset,
- data.data,
- sizeof(data.data));
- if (retval < 0) {
- touch_count = 0;
- goto exit;
- }
-
- x = (data.x_position_11_4 << 4) | data.x_position_3_0;
- y = (data.y_position_11_4 << 4) | data.y_position_3_0;
- wx = data.wx;
- wy = data.wy;
-
- if (rmi4_data->hw_if->board_data->swap_axes) {
- temp = x;
- x = y;
- y = temp;
- temp = wx;
- wx = wy;
- wy = temp;
- }
-
- if (rmi4_data->hw_if->board_data->x_flip)
- x = rmi4_data->sensor_max_x - x;
- if (rmi4_data->hw_if->board_data->y_flip)
- y = rmi4_data->sensor_max_y - y;
-
- input_report_key(rmi4_data->input_dev,
- BTN_TOUCH, 1);
- input_report_key(rmi4_data->input_dev,
- BTN_TOOL_FINGER, 1);
- input_report_abs(rmi4_data->input_dev,
- ABS_MT_POSITION_X, x);
- input_report_abs(rmi4_data->input_dev,
- ABS_MT_POSITION_Y, y);
-#ifdef REPORT_2D_W
- input_report_abs(rmi4_data->input_dev,
- ABS_MT_TOUCH_MAJOR, max(wx, wy));
- input_report_abs(rmi4_data->input_dev,
- ABS_MT_TOUCH_MINOR, min(wx, wy));
-#endif
-#ifndef TYPE_B_PROTOCOL
- input_mt_sync(rmi4_data->input_dev);
-#endif
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Finger %d: status = 0x%02x, x = %d, y = %d, wx = %d, wy = %d\n",
- __func__, finger,
- finger_status,
- x, y, wx, wy);
-
- touch_count++;
- }
- }
-
- if (touch_count == 0) {
- input_report_key(rmi4_data->input_dev,
- BTN_TOUCH, 0);
- input_report_key(rmi4_data->input_dev,
- BTN_TOOL_FINGER, 0);
-#ifndef TYPE_B_PROTOCOL
- input_mt_sync(rmi4_data->input_dev);
-#endif
- }
-
- input_sync(rmi4_data->input_dev);
-
-exit:
- mutex_unlock(&(rmi4_data->rmi4_report_mutex));
-
- return touch_count;
-}
-
-static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn *fhandler)
-{
- int retval;
- unsigned char touch_count = 0; /* number of touch points */
- unsigned char index;
- unsigned char finger;
- unsigned char fingers_to_process;
- unsigned char finger_status;
- unsigned char size_of_2d_data;
- unsigned char gesture_type;
- unsigned short data_addr;
- int x;
- int y;
- int wx;
- int wy;
- int temp;
-#ifdef REPORT_2D_PRESSURE
- int pressure;
-#endif
- struct synaptics_rmi4_f12_extra_data *extra_data;
- struct synaptics_rmi4_f12_finger_data *data;
- struct synaptics_rmi4_f12_finger_data *finger_data;
- static unsigned char finger_presence;
- static unsigned char stylus_presence;
-#ifdef F12_DATA_15_WORKAROUND
- static unsigned char objects_already_present;
-#endif
-
- fingers_to_process = fhandler->num_of_data_points;
- data_addr = fhandler->full_addr.data_base;
- extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
- size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
-
- if (rmi4_data->suspend && rmi4_data->enable_wakeup_gesture) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- data_addr + extra_data->data4_offset,
- rmi4_data->gesture_detection,
- sizeof(rmi4_data->gesture_detection));
- if (retval < 0)
- return 0;
-
- gesture_type = rmi4_data->gesture_detection[0];
-
- if (gesture_type && gesture_type != F12_UDG_DETECT) {
- input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 1);
- input_sync(rmi4_data->input_dev);
- input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 0);
- input_sync(rmi4_data->input_dev);
- rmi4_data->suspend = false;
- }
-
- return 0;
- }
-
- /* Determine the total number of fingers to process */
- if (extra_data->data15_size) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- data_addr + extra_data->data15_offset,
- extra_data->data15_data,
- extra_data->data15_size);
- if (retval < 0)
- return 0;
-
- /* Start checking from the highest bit */
- index = extra_data->data15_size - 1; /* Highest byte */
- finger = (fingers_to_process - 1) % 8; /* Highest bit */
- do {
- if (extra_data->data15_data[index] & (1 << finger))
- break;
-
- if (finger) {
- finger--;
- } else if (index > 0) {
- index--; /* Move to the next lower byte */
- finger = 7;
- }
-
- fingers_to_process--;
- } while (fingers_to_process);
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Number of fingers to process = %d\n",
- __func__, fingers_to_process);
- }
-
-#ifdef F12_DATA_15_WORKAROUND
- fingers_to_process = max(fingers_to_process, objects_already_present);
-#endif
-
- if (!fingers_to_process) {
- synaptics_rmi4_free_fingers(rmi4_data);
- finger_presence = 0;
- stylus_presence = 0;
- return 0;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- data_addr + extra_data->data1_offset,
- (unsigned char *)fhandler->data,
- fingers_to_process * size_of_2d_data);
- if (retval < 0)
- return 0;
-
- data = (struct synaptics_rmi4_f12_finger_data *)fhandler->data;
-
-#ifdef REPORT_2D_PRESSURE
- if (rmi4_data->report_pressure) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- data_addr + extra_data->data23_offset,
- extra_data->data23_data,
- fingers_to_process);
- if (retval < 0)
- return 0;
- }
-#endif
-
- mutex_lock(&(rmi4_data->rmi4_report_mutex));
-
- for (finger = 0; finger < fingers_to_process; finger++) {
- finger_data = data + finger;
- finger_status = finger_data->object_type_and_status;
-
-#ifdef F12_DATA_15_WORKAROUND
- objects_already_present = finger + 1;
-#endif
-
- x = (finger_data->x_msb << 8) | (finger_data->x_lsb);
- y = (finger_data->y_msb << 8) | (finger_data->y_lsb);
-#ifdef REPORT_2D_W
- wx = finger_data->wx;
- wy = finger_data->wy;
-#endif
-
- if (rmi4_data->hw_if->board_data->swap_axes) {
- temp = x;
- x = y;
- y = temp;
- temp = wx;
- wx = wy;
- wy = temp;
- }
-
- if (rmi4_data->hw_if->board_data->x_flip)
- x = rmi4_data->sensor_max_x - x;
- if (rmi4_data->hw_if->board_data->y_flip)
- y = rmi4_data->sensor_max_y - y;
-
- switch (finger_status) {
- case F12_FINGER_STATUS:
- case F12_GLOVED_FINGER_STATUS:
- /* Stylus has priority over fingers */
- if (stylus_presence)
- break;
-#ifdef TYPE_B_PROTOCOL
- input_mt_slot(rmi4_data->input_dev, finger);
- input_mt_report_slot_state(rmi4_data->input_dev,
- MT_TOOL_FINGER, 1);
-#endif
-
- input_report_key(rmi4_data->input_dev,
- BTN_TOUCH, 1);
- input_report_key(rmi4_data->input_dev,
- BTN_TOOL_FINGER, 1);
- input_report_abs(rmi4_data->input_dev,
- ABS_MT_POSITION_X, x);
- input_report_abs(rmi4_data->input_dev,
- ABS_MT_POSITION_Y, y);
-#ifdef REPORT_2D_W
- if (rmi4_data->wedge_sensor) {
- input_report_abs(rmi4_data->input_dev,
- ABS_MT_TOUCH_MAJOR, wx);
- input_report_abs(rmi4_data->input_dev,
- ABS_MT_TOUCH_MINOR, wx);
- } else {
- input_report_abs(rmi4_data->input_dev,
- ABS_MT_TOUCH_MAJOR,
- max(wx, wy));
- input_report_abs(rmi4_data->input_dev,
- ABS_MT_TOUCH_MINOR,
- min(wx, wy));
- }
-#endif
-#ifdef REPORT_2D_PRESSURE
- if (rmi4_data->report_pressure) {
- pressure = extra_data->data23_data[finger];
- input_report_abs(rmi4_data->input_dev,
- ABS_MT_PRESSURE, pressure);
- }
-#endif
-#ifndef TYPE_B_PROTOCOL
- input_mt_sync(rmi4_data->input_dev);
-#endif
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Finger %d: status = 0x%02x, x = %d, y = %d, wx = %d, wy = %d\n",
- __func__, finger,
- finger_status,
- x, y, wx, wy);
-
- finger_presence = 1;
- touch_count++;
- break;
- case F12_PALM_STATUS:
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Finger %d: x = %d, y = %d, wx = %d, wy = %d\n",
- __func__, finger,
- x, y, wx, wy);
- break;
- case F12_STYLUS_STATUS:
- case F12_ERASER_STATUS:
- if (!rmi4_data->stylus_enable)
- break;
- /* Stylus has priority over fingers */
- if (finger_presence) {
- mutex_unlock(&(rmi4_data->rmi4_report_mutex));
- synaptics_rmi4_free_fingers(rmi4_data);
- mutex_lock(&(rmi4_data->rmi4_report_mutex));
- finger_presence = 0;
- }
- if (stylus_presence) {/* Allow one stylus at a timee */
- if (finger + 1 != stylus_presence)
- break;
- }
- input_report_key(rmi4_data->stylus_dev,
- BTN_TOUCH, 1);
- if (finger_status == F12_STYLUS_STATUS) {
- input_report_key(rmi4_data->stylus_dev,
- BTN_TOOL_PEN, 1);
- } else {
- input_report_key(rmi4_data->stylus_dev,
- BTN_TOOL_RUBBER, 1);
- }
- input_report_abs(rmi4_data->stylus_dev,
- ABS_X, x);
- input_report_abs(rmi4_data->stylus_dev,
- ABS_Y, y);
- input_sync(rmi4_data->stylus_dev);
-
- stylus_presence = finger + 1;
- touch_count++;
- break;
- default:
-#ifdef TYPE_B_PROTOCOL
- input_mt_slot(rmi4_data->input_dev, finger);
- input_mt_report_slot_state(rmi4_data->input_dev,
- MT_TOOL_FINGER, 0);
-#endif
- break;
- }
- }
-
- if (touch_count == 0) {
- finger_presence = 0;
-#ifdef F12_DATA_15_WORKAROUND
- objects_already_present = 0;
-#endif
- input_report_key(rmi4_data->input_dev,
- BTN_TOUCH, 0);
- input_report_key(rmi4_data->input_dev,
- BTN_TOOL_FINGER, 0);
-#ifndef TYPE_B_PROTOCOL
- input_mt_sync(rmi4_data->input_dev);
-#endif
-
- if (rmi4_data->stylus_enable) {
- stylus_presence = 0;
- input_report_key(rmi4_data->stylus_dev,
- BTN_TOUCH, 0);
- input_report_key(rmi4_data->stylus_dev,
- BTN_TOOL_PEN, 0);
- if (rmi4_data->eraser_enable) {
- input_report_key(rmi4_data->stylus_dev,
- BTN_TOOL_RUBBER, 0);
- }
- input_sync(rmi4_data->stylus_dev);
- }
- }
-
- input_sync(rmi4_data->input_dev);
-
- mutex_unlock(&(rmi4_data->rmi4_report_mutex));
-
- return touch_count;
-}
-
-static void synaptics_rmi4_f1a_report(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn *fhandler)
-{
- int retval;
- unsigned char touch_count = 0;
- unsigned char button;
- unsigned char index;
- unsigned char shift;
- unsigned char status;
- unsigned char *data;
- unsigned short data_addr = fhandler->full_addr.data_base;
- struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
- static unsigned char do_once = 1;
- static bool current_status[MAX_NUMBER_OF_BUTTONS];
-#ifdef NO_0D_WHILE_2D
- static bool before_2d_status[MAX_NUMBER_OF_BUTTONS];
- static bool while_2d_status[MAX_NUMBER_OF_BUTTONS];
-#endif
-
- if (do_once) {
- memset(current_status, 0, sizeof(current_status));
-#ifdef NO_0D_WHILE_2D
- memset(before_2d_status, 0, sizeof(before_2d_status));
- memset(while_2d_status, 0, sizeof(while_2d_status));
-#endif
- do_once = 0;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- data_addr,
- f1a->button_data_buffer,
- f1a->button_bitmask_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read button data registers\n",
- __func__);
- return;
- }
-
- data = f1a->button_data_buffer;
-
- mutex_lock(&(rmi4_data->rmi4_report_mutex));
-
- for (button = 0; button < f1a->valid_button_count; button++) {
- index = button / 8;
- shift = button % 8;
- status = ((data[index] >> shift) & MASK_1BIT);
-
- if (current_status[button] == status)
- continue;
- else
- current_status[button] = status;
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Button %d (code %d) ->%d\n",
- __func__, button,
- f1a->button_map[button],
- status);
-#ifdef NO_0D_WHILE_2D
- if (rmi4_data->fingers_on_2d == false) {
- if (status == 1) {
- before_2d_status[button] = 1;
- } else {
- if (while_2d_status[button] == 1) {
- while_2d_status[button] = 0;
- continue;
- } else {
- before_2d_status[button] = 0;
- }
- }
- touch_count++;
- input_report_key(rmi4_data->input_dev,
- f1a->button_map[button],
- status);
- } else {
- if (before_2d_status[button] == 1) {
- before_2d_status[button] = 0;
- touch_count++;
- input_report_key(rmi4_data->input_dev,
- f1a->button_map[button],
- status);
- } else {
- if (status == 1)
- while_2d_status[button] = 1;
- else
- while_2d_status[button] = 0;
- }
- }
-#else
- touch_count++;
- input_report_key(rmi4_data->input_dev,
- f1a->button_map[button],
- status);
-#endif
- }
-
- if (touch_count)
- input_sync(rmi4_data->input_dev);
-
- mutex_unlock(&(rmi4_data->rmi4_report_mutex));
-
- return;
-}
-
-static void synaptics_rmi4_report_touch(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn *fhandler)
-{
- unsigned char touch_count_2d;
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Function %02x reporting\n",
- __func__, fhandler->fn_number);
-
- switch (fhandler->fn_number) {
- case SYNAPTICS_RMI4_F11:
- touch_count_2d = synaptics_rmi4_f11_abs_report(rmi4_data,
- fhandler);
-
- if (touch_count_2d)
- rmi4_data->fingers_on_2d = true;
- else
- rmi4_data->fingers_on_2d = false;
- break;
- case SYNAPTICS_RMI4_F12:
- touch_count_2d = synaptics_rmi4_f12_abs_report(rmi4_data,
- fhandler);
-
- if (touch_count_2d)
- rmi4_data->fingers_on_2d = true;
- else
- rmi4_data->fingers_on_2d = false;
- break;
- case SYNAPTICS_RMI4_F1A:
- synaptics_rmi4_f1a_report(rmi4_data, fhandler);
- break;
- default:
- break;
- }
-
- return;
-}
-
-static void synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *rmi4_data,
- bool report)
-{
- int retval;
- unsigned char data[MAX_INTR_REGISTERS + 1];
- unsigned char *intr = &data[1];
- bool was_in_bl_mode;
- struct synaptics_rmi4_f01_device_status status;
- struct synaptics_rmi4_fn *fhandler;
- struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- struct synaptics_rmi4_device_info *rmi;
-
- rmi = &(rmi4_data->rmi4_mod_info);
-
- if (rmi4_data->stay_awake) {
- msleep(30);
- return;
- }
-
- /*
- * Get interrupt status information from F01 Data1 register to
- * determine the source(s) that are flagging the interrupt.
- */
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_data_base_addr,
- data,
- rmi4_data->num_of_intr_regs + 1);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read interrupt status\n",
- __func__);
- return;
- }
-
- status.data[0] = data[0];
- if (status.status_code == STATUS_CRC_IN_PROGRESS) {
- retval = synaptics_rmi4_check_status(rmi4_data,
- &was_in_bl_mode);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to check status\n",
- __func__);
- return;
- }
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_data_base_addr,
- status.data,
- sizeof(status.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read device status\n",
- __func__);
- return;
- }
- }
- if (status.unconfigured && !status.flash_prog) {
- pr_notice("%s: spontaneous reset detected\n", __func__);
- }
-
- if (!report)
- return;
-
- /*
- * Traverse the function handler list and service the source(s)
- * of the interrupt accordingly.
- */
- if (!list_empty(&rmi->support_fn_list)) {
- list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- if (fhandler->num_of_data_sources) {
- if (fhandler->intr_mask &
- intr[fhandler->intr_reg_num]) {
- synaptics_rmi4_report_touch(rmi4_data,
- fhandler);
- }
- }
- }
- }
-
- mutex_lock(&exp_data.mutex);
- if (!list_empty(&exp_data.list)) {
- list_for_each_entry(exp_fhandler, &exp_data.list, link) {
- if (!exp_fhandler->insert &&
- !exp_fhandler->remove &&
- (exp_fhandler->exp_fn->attn != NULL))
- exp_fhandler->exp_fn->attn(rmi4_data, intr[0]);
- }
- }
- mutex_unlock(&exp_data.mutex);
-
- return;
-}
-
-static irqreturn_t synaptics_rmi4_irq(int irq, void *data)
-{
- struct synaptics_rmi4_data *rmi4_data = data;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- if (synaptics_filter_interrupt(data) == IRQ_HANDLED)
- return IRQ_HANDLED;
-
- if (gpio_get_value(bdata->irq_gpio) != bdata->irq_on_state)
- goto exit;
-
- synaptics_rmi4_sensor_report(rmi4_data, true);
-
-exit:
- return IRQ_HANDLED;
-}
-
-static int synaptics_rmi4_int_enable(struct synaptics_rmi4_data *rmi4_data,
- bool enable)
-{
- int retval = 0;
- unsigned char ii;
- unsigned char zero = 0x00;
- unsigned char *intr_mask;
- unsigned short intr_addr;
-
- intr_mask = rmi4_data->intr_mask;
-
- for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) {
- if (intr_mask[ii] != 0x00) {
- intr_addr = rmi4_data->f01_ctrl_base_addr + 1 + ii;
- if (enable) {
- retval = synaptics_rmi4_reg_write(rmi4_data,
- intr_addr,
- &(intr_mask[ii]),
- sizeof(intr_mask[ii]));
- if (retval < 0)
- return retval;
- } else {
- retval = synaptics_rmi4_reg_write(rmi4_data,
- intr_addr,
- &zero,
- sizeof(zero));
- if (retval < 0)
- return retval;
- }
- }
- }
-
- return retval;
-}
-
-static int synaptics_rmi4_irq_enable(struct synaptics_rmi4_data *rmi4_data,
- bool enable, bool attn_only)
-{
- int retval = 0;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- if (attn_only) {
- retval = synaptics_rmi4_int_enable(rmi4_data, enable);
- return retval;
- }
-
- if (enable) {
- if (rmi4_data->irq_enabled)
- return retval;
-
- retval = synaptics_rmi4_int_enable(rmi4_data, false);
- if (retval < 0)
- return retval;
-
- /* Process and clear interrupts */
- synaptics_rmi4_sensor_report(rmi4_data, false);
-
- retval = request_threaded_irq(rmi4_data->irq, NULL,
- synaptics_rmi4_irq, bdata->irq_flags,
- PLATFORM_DRIVER_NAME, rmi4_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create irq thread\n",
- __func__);
- return retval;
- }
-
- retval = synaptics_rmi4_int_enable(rmi4_data, true);
- if (retval < 0)
- return retval;
-
- rmi4_data->irq_enabled = true;
- } else {
- if (rmi4_data->irq_enabled) {
- disable_irq(rmi4_data->irq);
- free_irq(rmi4_data->irq, rmi4_data);
- rmi4_data->irq_enabled = false;
- }
- }
-
- return retval;
-}
-
-static void synaptics_rmi4_set_intr_mask(struct synaptics_rmi4_fn *fhandler,
- struct synaptics_rmi4_fn_desc *fd,
- unsigned int intr_count)
-{
- unsigned char ii;
- unsigned char intr_offset;
-
- fhandler->intr_reg_num = (intr_count + 7) / 8;
- if (fhandler->intr_reg_num != 0)
- fhandler->intr_reg_num -= 1;
-
- /* Set an enable bit for each data source */
- intr_offset = intr_count % 8;
- fhandler->intr_mask = 0;
- for (ii = intr_offset;
- ii < (fd->intr_src_count + intr_offset);
- ii++)
- fhandler->intr_mask |= 1 << ii;
-
- return;
-}
-
-static int synaptics_rmi4_f01_init(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn *fhandler,
- struct synaptics_rmi4_fn_desc *fd,
- unsigned int intr_count)
-{
- fhandler->fn_number = fd->fn_number;
- fhandler->num_of_data_sources = fd->intr_src_count;
- fhandler->data = NULL;
- fhandler->extra = NULL;
-
- synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
-
- rmi4_data->f01_query_base_addr = fd->query_base_addr;
- rmi4_data->f01_ctrl_base_addr = fd->ctrl_base_addr;
- rmi4_data->f01_data_base_addr = fd->data_base_addr;
- rmi4_data->f01_cmd_base_addr = fd->cmd_base_addr;
-
- return 0;
-}
-
-static int synaptics_rmi4_f11_init(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn *fhandler,
- struct synaptics_rmi4_fn_desc *fd,
- unsigned int intr_count)
-{
- int retval;
- int temp;
- unsigned char offset;
- unsigned char fingers_supported;
- struct synaptics_rmi4_f11_extra_data *extra_data;
- struct synaptics_rmi4_f11_query_0_5 query_0_5;
- struct synaptics_rmi4_f11_query_7_8 query_7_8;
- struct synaptics_rmi4_f11_query_9 query_9;
- struct synaptics_rmi4_f11_query_12 query_12;
- struct synaptics_rmi4_f11_query_27 query_27;
- struct synaptics_rmi4_f11_ctrl_6_9 control_6_9;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- fhandler->fn_number = fd->fn_number;
- fhandler->num_of_data_sources = fd->intr_src_count;
- fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL);
- if (!fhandler->extra) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for fhandler->extra\n",
- __func__);
- return -ENOMEM;
- }
- extra_data = (struct synaptics_rmi4_f11_extra_data *)fhandler->extra;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.query_base,
- query_0_5.data,
- sizeof(query_0_5.data));
- if (retval < 0)
- return retval;
-
- /* Maximum number of fingers supported */
- if (query_0_5.num_of_fingers <= 4)
- fhandler->num_of_data_points = query_0_5.num_of_fingers + 1;
- else if (query_0_5.num_of_fingers == 5)
- fhandler->num_of_data_points = 10;
-
- rmi4_data->num_of_fingers = fhandler->num_of_data_points;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.ctrl_base + 6,
- control_6_9.data,
- sizeof(control_6_9.data));
- if (retval < 0)
- return retval;
-
- /* Maximum x and y */
- rmi4_data->sensor_max_x = control_6_9.sensor_max_x_pos_7_0 |
- (control_6_9.sensor_max_x_pos_11_8 << 8);
- rmi4_data->sensor_max_y = control_6_9.sensor_max_y_pos_7_0 |
- (control_6_9.sensor_max_y_pos_11_8 << 8);
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Function %02x max x = %d max y = %d\n",
- __func__, fhandler->fn_number,
- rmi4_data->sensor_max_x,
- rmi4_data->sensor_max_y);
-
- rmi4_data->max_touch_width = MAX_F11_TOUCH_WIDTH;
-
- if (bdata->swap_axes) {
- temp = rmi4_data->sensor_max_x;
- rmi4_data->sensor_max_x = rmi4_data->sensor_max_y;
- rmi4_data->sensor_max_y = temp;
- }
-
- synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
-
- fhandler->data = NULL;
-
- offset = sizeof(query_0_5.data);
-
- /* query 6 */
- if (query_0_5.has_rel)
- offset += 1;
-
- /* queries 7 8 */
- if (query_0_5.has_gestures) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.query_base + offset,
- query_7_8.data,
- sizeof(query_7_8.data));
- if (retval < 0)
- return retval;
-
- offset += sizeof(query_7_8.data);
- }
-
- /* query 9 */
- if (query_0_5.has_query_9) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.query_base + offset,
- query_9.data,
- sizeof(query_9.data));
- if (retval < 0)
- return retval;
-
- offset += sizeof(query_9.data);
- }
-
- /* query 10 */
- if (query_0_5.has_gestures && query_7_8.has_touch_shapes)
- offset += 1;
-
- /* query 11 */
- if (query_0_5.has_query_11)
- offset += 1;
-
- /* query 12 */
- if (query_0_5.has_query_12) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.query_base + offset,
- query_12.data,
- sizeof(query_12.data));
- if (retval < 0)
- return retval;
-
- offset += sizeof(query_12.data);
- }
-
- /* query 13 */
- if (query_0_5.has_jitter_filter)
- offset += 1;
-
- /* query 14 */
- if (query_0_5.has_query_12 && query_12.has_general_information_2)
- offset += 1;
-
- /* queries 15 16 17 18 19 20 21 22 23 24 25 26*/
- if (query_0_5.has_query_12 && query_12.has_physical_properties)
- offset += 12;
-
- /* query 27 */
- if (query_0_5.has_query_27) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.query_base + offset,
- query_27.data,
- sizeof(query_27.data));
- if (retval < 0)
- return retval;
-
- rmi4_data->f11_wakeup_gesture = query_27.has_wakeup_gesture;
- }
-
- if (!rmi4_data->f11_wakeup_gesture)
- return retval;
-
- /* data 0 */
- fingers_supported = fhandler->num_of_data_points;
- offset = (fingers_supported + 3) / 4;
-
- /* data 1 2 3 4 5 */
- offset += 5 * fingers_supported;
-
- /* data 6 7 */
- if (query_0_5.has_rel)
- offset += 2 * fingers_supported;
-
- /* data 8 */
- if (query_0_5.has_gestures && query_7_8.data[0])
- offset += 1;
-
- /* data 9 */
- if (query_0_5.has_gestures && (query_7_8.data[0] || query_7_8.data[1]))
- offset += 1;
-
- /* data 10 */
- if (query_0_5.has_gestures &&
- (query_7_8.has_pinch || query_7_8.has_flick))
- offset += 1;
-
- /* data 11 12 */
- if (query_0_5.has_gestures &&
- (query_7_8.has_flick || query_7_8.has_rotate))
- offset += 2;
-
- /* data 13 */
- if (query_0_5.has_gestures && query_7_8.has_touch_shapes)
- offset += (fingers_supported + 3) / 4;
-
- /* data 14 15 */
- if (query_0_5.has_gestures &&
- (query_7_8.has_scroll_zones ||
- query_7_8.has_multi_finger_scroll ||
- query_7_8.has_chiral_scroll))
- offset += 2;
-
- /* data 16 17 */
- if (query_0_5.has_gestures &&
- (query_7_8.has_scroll_zones &&
- query_7_8.individual_scroll_zones))
- offset += 2;
-
- /* data 18 19 20 21 22 23 24 25 26 27 */
- if (query_0_5.has_query_9 && query_9.has_contact_geometry)
- offset += 10 * fingers_supported;
-
- /* data 28 */
- if (query_0_5.has_bending_correction ||
- query_0_5.has_large_object_suppression)
- offset += 1;
-
- /* data 29 30 31 */
- if (query_0_5.has_query_9 && query_9.has_pen_hover_discrimination)
- offset += 3;
-
- /* data 32 */
- if (query_0_5.has_query_12 &&
- query_12.has_small_object_detection_tuning)
- offset += 1;
-
- /* data 33 34 */
- if (query_0_5.has_query_27 && query_27.f11_query27_b0)
- offset += 2;
-
- /* data 35 */
- if (query_0_5.has_query_12 && query_12.has_8bit_w)
- offset += fingers_supported;
-
- /* data 36 */
- if (query_0_5.has_bending_correction)
- offset += 1;
-
- /* data 37 */
- if (query_0_5.has_query_27 && query_27.has_data_37)
- offset += 1;
-
- /* data 38 */
- if (query_0_5.has_query_27 && query_27.has_wakeup_gesture)
- extra_data->data38_offset = offset;
-
- return retval;
-}
-
-static int synaptics_rmi4_f12_set_enables(struct synaptics_rmi4_data *rmi4_data,
- unsigned short ctrl28)
-{
- int retval;
- static unsigned short ctrl_28_address;
-
- if (ctrl28)
- ctrl_28_address = ctrl28;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- ctrl_28_address,
- &rmi4_data->report_enable,
- sizeof(rmi4_data->report_enable));
- if (retval < 0)
- return retval;
-
- return retval;
-}
-
-static int synaptics_rmi4_f12_ctrl_sub(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn *fhandler,
- struct synaptics_rmi4_f12_query_5 *query_5,
- unsigned char ctrlreg, unsigned char subpacket)
-{
- int retval;
- unsigned char cnt;
- unsigned char regnum;
- unsigned char bitnum;
- unsigned char q5_index;
- unsigned char q6_index;
- unsigned char offset;
- unsigned char max_ctrlreg;
- unsigned char *query_6;
-
- max_ctrlreg = (sizeof(query_5->data) - 1) * 8 - 1;
-
- if (ctrlreg > max_ctrlreg) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Control register number (%d) over limit\n",
- __func__, ctrlreg);
- return -EINVAL;
- }
-
- q5_index = ctrlreg / 8 + 1;
- bitnum = ctrlreg % 8;
- if ((query_5->data[q5_index] & (1 << bitnum)) == 0x00) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Control %d is not present\n",
- __func__, ctrlreg);
- return -EINVAL;
- }
-
- query_6 = kmalloc(query_5->size_of_query6, GFP_KERNEL);
- if (!query_6) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for query 6\n",
- __func__);
- return -ENOMEM;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.query_base + 6,
- query_6,
- query_5->size_of_query6);
- if (retval < 0)
- goto exit;
-
- q6_index = 0;
-
- for (regnum = 0; regnum < ctrlreg; regnum++) {
- q5_index = regnum / 8 + 1;
- bitnum = regnum % 8;
- if ((query_5->data[q5_index] & (1 << bitnum)) == 0x00)
- continue;
-
- if (query_6[q6_index] == 0x00)
- q6_index += 3;
- else
- q6_index++;
-
- while (query_6[q6_index] & ~MASK_7BIT)
- q6_index++;
-
- q6_index++;
- }
-
- cnt = 0;
- q6_index++;
- offset = subpacket / 7;
- bitnum = subpacket % 7;
-
- do {
- if (cnt == offset) {
- if (query_6[q6_index + cnt] & (1 << bitnum))
- retval = 1;
- else
- retval = 0;
- goto exit;
- }
- cnt++;
- } while (query_6[q6_index + cnt - 1] & ~MASK_7BIT);
-
- retval = 0;
-
-exit:
- kfree(query_6);
-
- return retval;
-}
-
-static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn *fhandler,
- struct synaptics_rmi4_fn_desc *fd,
- unsigned int intr_count)
-{
- int retval = 0;
- int temp;
- unsigned char subpacket;
- unsigned char ctrl_23_size;
- unsigned char size_of_2d_data;
- unsigned char size_of_query8;
- unsigned char ctrl_8_offset;
- unsigned char ctrl_20_offset;
- unsigned char ctrl_23_offset;
- unsigned char ctrl_28_offset;
- unsigned char ctrl_31_offset;
- unsigned char num_of_fingers;
- struct synaptics_rmi4_f12_extra_data *extra_data;
- struct synaptics_rmi4_f12_query_5 *query_5 = NULL;
- struct synaptics_rmi4_f12_query_8 *query_8 = NULL;
- struct synaptics_rmi4_f12_ctrl_8 *ctrl_8 = NULL;
- struct synaptics_rmi4_f12_ctrl_23 *ctrl_23 = NULL;
- struct synaptics_rmi4_f12_ctrl_31 *ctrl_31 = NULL;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- fhandler->fn_number = fd->fn_number;
- fhandler->num_of_data_sources = fd->intr_src_count;
- fhandler->extra = kmalloc(sizeof(*extra_data), GFP_KERNEL);
- if (!fhandler->extra) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for fhandler->extra\n",
- __func__);
- return -ENOMEM;
- }
- extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
- size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data);
-
- query_5 = kmalloc(sizeof(*query_5), GFP_KERNEL);
- if (!query_5) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for query_5\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- query_8 = kmalloc(sizeof(*query_8), GFP_KERNEL);
- if (!query_8) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for query_8\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- ctrl_8 = kmalloc(sizeof(*ctrl_8), GFP_KERNEL);
- if (!ctrl_8) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for ctrl_8\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- ctrl_23 = kmalloc(sizeof(*ctrl_23), GFP_KERNEL);
- if (!ctrl_23) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for ctrl_23\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- ctrl_31 = kmalloc(sizeof(*ctrl_31), GFP_KERNEL);
- if (!ctrl_31) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for ctrl_31\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.query_base + 5,
- query_5->data,
- sizeof(query_5->data));
- if (retval < 0)
- goto exit;
-
- ctrl_8_offset = query_5->ctrl0_is_present +
- query_5->ctrl1_is_present +
- query_5->ctrl2_is_present +
- query_5->ctrl3_is_present +
- query_5->ctrl4_is_present +
- query_5->ctrl5_is_present +
- query_5->ctrl6_is_present +
- query_5->ctrl7_is_present;
-
- ctrl_20_offset = ctrl_8_offset +
- query_5->ctrl8_is_present +
- query_5->ctrl9_is_present +
- query_5->ctrl10_is_present +
- query_5->ctrl11_is_present +
- query_5->ctrl12_is_present +
- query_5->ctrl13_is_present +
- query_5->ctrl14_is_present +
- query_5->ctrl15_is_present +
- query_5->ctrl16_is_present +
- query_5->ctrl17_is_present +
- query_5->ctrl18_is_present +
- query_5->ctrl19_is_present;
-
- ctrl_23_offset = ctrl_20_offset +
- query_5->ctrl20_is_present +
- query_5->ctrl21_is_present +
- query_5->ctrl22_is_present;
-
- ctrl_28_offset = ctrl_23_offset +
- query_5->ctrl23_is_present +
- query_5->ctrl24_is_present +
- query_5->ctrl25_is_present +
- query_5->ctrl26_is_present +
- query_5->ctrl27_is_present;
-
- ctrl_31_offset = ctrl_28_offset +
- query_5->ctrl28_is_present +
- query_5->ctrl29_is_present +
- query_5->ctrl30_is_present;
-
- ctrl_23_size = 2;
- for (subpacket = 2; subpacket <= 4; subpacket++) {
- retval = synaptics_rmi4_f12_ctrl_sub(rmi4_data,
- fhandler, query_5, 23, subpacket);
- if (retval == 1)
- ctrl_23_size++;
- else if (retval < 0)
- goto exit;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.ctrl_base + ctrl_23_offset,
- ctrl_23->data,
- ctrl_23_size);
- if (retval < 0)
- goto exit;
-
- /* Maximum number of fingers supported */
- fhandler->num_of_data_points = min_t(unsigned char,
- ctrl_23->max_reported_objects,
- (unsigned char)F12_FINGERS_TO_SUPPORT);
-
- num_of_fingers = fhandler->num_of_data_points;
- rmi4_data->num_of_fingers = num_of_fingers;
-
- rmi4_data->stylus_enable = ctrl_23->stylus_enable;
- rmi4_data->eraser_enable = ctrl_23->eraser_enable;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.query_base + 7,
- &size_of_query8,
- sizeof(size_of_query8));
- if (retval < 0)
- goto exit;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.query_base + 8,
- query_8->data,
- size_of_query8);
- if (retval < 0)
- goto exit;
-
- /* Determine the presence of the Data0 register */
- extra_data->data1_offset = query_8->data0_is_present;
-
- if ((size_of_query8 >= 3) && (query_8->data15_is_present)) {
- extra_data->data15_offset = query_8->data0_is_present +
- query_8->data1_is_present +
- query_8->data2_is_present +
- query_8->data3_is_present +
- query_8->data4_is_present +
- query_8->data5_is_present +
- query_8->data6_is_present +
- query_8->data7_is_present +
- query_8->data8_is_present +
- query_8->data9_is_present +
- query_8->data10_is_present +
- query_8->data11_is_present +
- query_8->data12_is_present +
- query_8->data13_is_present +
- query_8->data14_is_present;
- extra_data->data15_size = (num_of_fingers + 7) / 8;
- } else {
- extra_data->data15_size = 0;
- }
-
-#ifdef REPORT_2D_PRESSURE
- if ((size_of_query8 >= 4) && (query_8->data23_is_present)) {
- extra_data->data23_offset = query_8->data0_is_present +
- query_8->data1_is_present +
- query_8->data2_is_present +
- query_8->data3_is_present +
- query_8->data4_is_present +
- query_8->data5_is_present +
- query_8->data6_is_present +
- query_8->data7_is_present +
- query_8->data8_is_present +
- query_8->data9_is_present +
- query_8->data10_is_present +
- query_8->data11_is_present +
- query_8->data12_is_present +
- query_8->data13_is_present +
- query_8->data14_is_present +
- query_8->data15_is_present +
- query_8->data16_is_present +
- query_8->data17_is_present +
- query_8->data18_is_present +
- query_8->data19_is_present +
- query_8->data20_is_present +
- query_8->data21_is_present +
- query_8->data22_is_present;
- extra_data->data23_size = num_of_fingers;
- rmi4_data->report_pressure = true;
- } else {
- extra_data->data23_size = 0;
- rmi4_data->report_pressure = false;
- }
-#endif
-
- rmi4_data->report_enable = RPT_DEFAULT;
-#ifdef REPORT_2D_Z
- rmi4_data->report_enable |= RPT_Z;
-#endif
-#ifdef REPORT_2D_W
- rmi4_data->report_enable |= (RPT_WX | RPT_WY);
-#endif
-
- retval = synaptics_rmi4_f12_set_enables(rmi4_data,
- fhandler->full_addr.ctrl_base + ctrl_28_offset);
- if (retval < 0)
- goto exit;
-
- if (query_5->ctrl8_is_present) {
- rmi4_data->wedge_sensor = false;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.ctrl_base + ctrl_8_offset,
- ctrl_8->data,
- sizeof(ctrl_8->data));
- if (retval < 0)
- goto exit;
-
- /* Maximum x and y */
- rmi4_data->sensor_max_x =
- ((unsigned int)ctrl_8->max_x_coord_lsb << 0) |
- ((unsigned int)ctrl_8->max_x_coord_msb << 8);
- rmi4_data->sensor_max_y =
- ((unsigned int)ctrl_8->max_y_coord_lsb << 0) |
- ((unsigned int)ctrl_8->max_y_coord_msb << 8);
-
- rmi4_data->max_touch_width = MAX_F12_TOUCH_WIDTH;
- } else {
- rmi4_data->wedge_sensor = true;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.ctrl_base + ctrl_31_offset,
- ctrl_31->data,
- sizeof(ctrl_31->data));
- if (retval < 0)
- goto exit;
-
- /* Maximum x and y */
- rmi4_data->sensor_max_x =
- ((unsigned int)ctrl_31->max_x_coord_lsb << 0) |
- ((unsigned int)ctrl_31->max_x_coord_msb << 8);
- rmi4_data->sensor_max_y =
- ((unsigned int)ctrl_31->max_y_coord_lsb << 0) |
- ((unsigned int)ctrl_31->max_y_coord_msb << 8);
-
- rmi4_data->max_touch_width = MAX_F12_TOUCH_WIDTH;
- }
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Function %02x max x = %d max y = %d\n",
- __func__, fhandler->fn_number,
- rmi4_data->sensor_max_x,
- rmi4_data->sensor_max_y);
-
- if (bdata->swap_axes) {
- temp = rmi4_data->sensor_max_x;
- rmi4_data->sensor_max_x = rmi4_data->sensor_max_y;
- rmi4_data->sensor_max_y = temp;
- }
-
- rmi4_data->f12_wakeup_gesture = query_5->ctrl27_is_present;
- if (rmi4_data->f12_wakeup_gesture) {
- extra_data->ctrl20_offset = ctrl_20_offset;
- extra_data->data4_offset = query_8->data0_is_present +
- query_8->data1_is_present +
- query_8->data2_is_present +
- query_8->data3_is_present;
- }
-
- synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
-
- /* Allocate memory for finger data storage space */
- fhandler->data_size = num_of_fingers * size_of_2d_data;
- fhandler->data = kmalloc(fhandler->data_size, GFP_KERNEL);
- if (!fhandler->data) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for fhandler->data\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
-exit:
- kfree(query_5);
- kfree(query_8);
- kfree(ctrl_8);
- kfree(ctrl_23);
- kfree(ctrl_31);
-
- return retval;
-}
-
-static int synaptics_rmi4_f1a_alloc_mem(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn *fhandler)
-{
- int retval;
- struct synaptics_rmi4_f1a_handle *f1a;
-
- f1a = kzalloc(sizeof(*f1a), GFP_KERNEL);
- if (!f1a) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for function handle\n",
- __func__);
- return -ENOMEM;
- }
-
- fhandler->data = (void *)f1a;
- fhandler->extra = NULL;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.query_base,
- f1a->button_query.data,
- sizeof(f1a->button_query.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read query registers\n",
- __func__);
- return retval;
- }
-
- f1a->max_count = f1a->button_query.max_button_count + 1;
-
- f1a->button_control.txrx_map = kzalloc(f1a->max_count * 2, GFP_KERNEL);
- if (!f1a->button_control.txrx_map) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for tx rx mapping\n",
- __func__);
- return -ENOMEM;
- }
-
- f1a->button_bitmask_size = (f1a->max_count + 7) / 8;
-
- f1a->button_data_buffer = kcalloc(f1a->button_bitmask_size,
- sizeof(*(f1a->button_data_buffer)), GFP_KERNEL);
- if (!f1a->button_data_buffer) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for data buffer\n",
- __func__);
- return -ENOMEM;
- }
-
- f1a->button_map = kcalloc(f1a->max_count,
- sizeof(*(f1a->button_map)), GFP_KERNEL);
- if (!f1a->button_map) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for button map\n",
- __func__);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static int synaptics_rmi4_f1a_button_map(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn *fhandler)
-{
- int retval;
- unsigned char ii;
- unsigned char offset = 0;
- struct synaptics_rmi4_f1a_query_4 query_4;
- struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- offset = f1a->button_query.has_general_control +
- f1a->button_query.has_interrupt_enable +
- f1a->button_query.has_multibutton_select;
-
- if (f1a->button_query.has_tx_rx_map) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.ctrl_base + offset,
- f1a->button_control.txrx_map,
- f1a->max_count * 2);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read tx rx mapping\n",
- __func__);
- return retval;
- }
-
- rmi4_data->button_txrx_mapping = f1a->button_control.txrx_map;
- }
-
- if (f1a->button_query.has_query4) {
- offset = 2 + f1a->button_query.has_query2 +
- f1a->button_query.has_query3;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.query_base + offset,
- query_4.data,
- sizeof(query_4.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read button features 4\n",
- __func__);
- return retval;
- }
-
- if (query_4.has_ctrl24)
- rmi4_data->external_afe_buttons = true;
- else
- rmi4_data->external_afe_buttons = false;
- }
-
- if (!bdata->cap_button_map) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: cap_button_map is NULL in board file\n",
- __func__);
- return -ENODEV;
- } else if (!bdata->cap_button_map->map) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Button map is missing in board file\n",
- __func__);
- return -ENODEV;
- } else {
- if (bdata->cap_button_map->nbuttons != f1a->max_count) {
- f1a->valid_button_count = min(f1a->max_count,
- bdata->cap_button_map->nbuttons);
- } else {
- f1a->valid_button_count = f1a->max_count;
- }
-
- for (ii = 0; ii < f1a->valid_button_count; ii++)
- f1a->button_map[ii] = bdata->cap_button_map->map[ii];
- }
-
- return 0;
-}
-
-static void synaptics_rmi4_f1a_kfree(struct synaptics_rmi4_fn *fhandler)
-{
- struct synaptics_rmi4_f1a_handle *f1a = fhandler->data;
-
- if (f1a) {
- kfree(f1a->button_control.txrx_map);
- kfree(f1a->button_data_buffer);
- kfree(f1a->button_map);
- kfree(f1a);
- fhandler->data = NULL;
- }
-
- return;
-}
-
-static int synaptics_rmi4_f1a_init(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn *fhandler,
- struct synaptics_rmi4_fn_desc *fd,
- unsigned int intr_count)
-{
- int retval;
-
- fhandler->fn_number = fd->fn_number;
- fhandler->num_of_data_sources = fd->intr_src_count;
-
- synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count);
-
- retval = synaptics_rmi4_f1a_alloc_mem(rmi4_data, fhandler);
- if (retval < 0)
- goto error_exit;
-
- retval = synaptics_rmi4_f1a_button_map(rmi4_data, fhandler);
- if (retval < 0)
- goto error_exit;
-
- rmi4_data->button_0d_enabled = 1;
-
- return 0;
-
-error_exit:
- synaptics_rmi4_f1a_kfree(fhandler);
-
- return retval;
-}
-
-static void synaptics_rmi4_empty_fn_list(struct synaptics_rmi4_data *rmi4_data)
-{
- struct synaptics_rmi4_fn *fhandler;
- struct synaptics_rmi4_fn *fhandler_temp;
- struct synaptics_rmi4_device_info *rmi;
-
- rmi = &(rmi4_data->rmi4_mod_info);
-
- if (!list_empty(&rmi->support_fn_list)) {
- list_for_each_entry_safe(fhandler,
- fhandler_temp,
- &rmi->support_fn_list,
- link) {
- if (fhandler->fn_number == SYNAPTICS_RMI4_F1A) {
- synaptics_rmi4_f1a_kfree(fhandler);
- } else {
- kfree(fhandler->extra);
- kfree(fhandler->data);
- }
- list_del(&fhandler->link);
- kfree(fhandler);
- }
- }
- INIT_LIST_HEAD(&rmi->support_fn_list);
-
- return;
-}
-
-static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data,
- bool *was_in_bl_mode)
-{
- int retval;
- int timeout = CHECK_STATUS_TIMEOUT_MS;
- struct synaptics_rmi4_f01_device_status status;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_data_base_addr,
- status.data,
- sizeof(status.data));
- if (retval < 0)
- return retval;
-
- while (status.status_code == STATUS_CRC_IN_PROGRESS) {
- if (timeout > 0)
- msleep(20);
- else
- return -EINVAL;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_data_base_addr,
- status.data,
- sizeof(status.data));
- if (retval < 0)
- return retval;
-
- timeout -= 20;
- }
-
- if (timeout != CHECK_STATUS_TIMEOUT_MS)
- *was_in_bl_mode = true;
-
- if (status.flash_prog == 1) {
- rmi4_data->flash_prog_mode = true;
- pr_notice("%s: In flash prog mode, status = 0x%02x\n",
- __func__,
- status.status_code);
- } else {
- rmi4_data->flash_prog_mode = false;
- }
-
- return 0;
-}
-
-static void synaptics_rmi4_set_configured(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- unsigned char device_ctrl;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_ctrl_base_addr,
- &device_ctrl,
- sizeof(device_ctrl));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set configured\n",
- __func__);
- return;
- }
-
- rmi4_data->no_sleep_setting = device_ctrl & NO_SLEEP_ON;
- device_ctrl |= CONFIGURED;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- rmi4_data->f01_ctrl_base_addr,
- &device_ctrl,
- sizeof(device_ctrl));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set configured\n",
- __func__);
- }
-
- return;
-}
-
-static int synaptics_rmi4_alloc_fh(struct synaptics_rmi4_fn **fhandler,
- struct synaptics_rmi4_fn_desc *rmi_fd, int page_number)
-{
- *fhandler = kmalloc(sizeof(**fhandler), GFP_KERNEL);
- if (!(*fhandler))
- return -ENOMEM;
-
- (*fhandler)->full_addr.data_base =
- (rmi_fd->data_base_addr |
- (page_number << 8));
- (*fhandler)->full_addr.ctrl_base =
- (rmi_fd->ctrl_base_addr |
- (page_number << 8));
- (*fhandler)->full_addr.cmd_base =
- (rmi_fd->cmd_base_addr |
- (page_number << 8));
- (*fhandler)->full_addr.query_base =
- (rmi_fd->query_base_addr |
- (page_number << 8));
-
- return 0;
-}
-
-static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- unsigned char page_number;
- unsigned char intr_count;
- unsigned char *f01_query;
- unsigned short pdt_entry_addr;
- bool f01found;
- bool f35found;
- bool was_in_bl_mode;
- struct synaptics_rmi4_fn_desc rmi_fd;
- struct synaptics_rmi4_fn *fhandler;
- struct synaptics_rmi4_device_info *rmi;
-
- rmi = &(rmi4_data->rmi4_mod_info);
-
-rescan_pdt:
- f01found = false;
- f35found = false;
- was_in_bl_mode = false;
- intr_count = 0;
- INIT_LIST_HEAD(&rmi->support_fn_list);
-
- /* Scan the page description tables of the pages to service */
- for (page_number = 0; page_number < PAGES_TO_SERVICE; page_number++) {
- for (pdt_entry_addr = PDT_START; pdt_entry_addr > PDT_END;
- pdt_entry_addr -= PDT_ENTRY_SIZE) {
- pdt_entry_addr |= (page_number << 8);
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- pdt_entry_addr,
- (unsigned char *)&rmi_fd,
- sizeof(rmi_fd));
- if (retval < 0)
- return retval;
-
- pdt_entry_addr &= ~(MASK_8BIT << 8);
-
- fhandler = NULL;
-
- if (rmi_fd.fn_number == 0) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Reached end of PDT\n",
- __func__);
- break;
- }
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: F%02x found (page %d)\n",
- __func__, rmi_fd.fn_number,
- page_number);
-
- switch (rmi_fd.fn_number) {
- case SYNAPTICS_RMI4_F01:
- if (rmi_fd.intr_src_count == 0)
- break;
-
- f01found = true;
-
- retval = synaptics_rmi4_alloc_fh(&fhandler,
- &rmi_fd, page_number);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc for F%d\n",
- __func__,
- rmi_fd.fn_number);
- return retval;
- }
-
- retval = synaptics_rmi4_f01_init(rmi4_data,
- fhandler, &rmi_fd, intr_count);
- if (retval < 0)
- return retval;
-
- retval = synaptics_rmi4_check_status(rmi4_data,
- &was_in_bl_mode);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to check status\n",
- __func__);
- return retval;
- }
-
- if (was_in_bl_mode) {
- kfree(fhandler);
- fhandler = NULL;
- goto rescan_pdt;
- }
-
- if (rmi4_data->flash_prog_mode)
- goto flash_prog_mode;
-
- break;
- case SYNAPTICS_RMI4_F11:
- if (rmi_fd.intr_src_count == 0)
- break;
-
- retval = synaptics_rmi4_alloc_fh(&fhandler,
- &rmi_fd, page_number);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc for F%d\n",
- __func__,
- rmi_fd.fn_number);
- return retval;
- }
-
- retval = synaptics_rmi4_f11_init(rmi4_data,
- fhandler, &rmi_fd, intr_count);
- if (retval < 0)
- return retval;
- break;
- case SYNAPTICS_RMI4_F12:
- if (rmi_fd.intr_src_count == 0)
- break;
-
- retval = synaptics_rmi4_alloc_fh(&fhandler,
- &rmi_fd, page_number);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc for F%d\n",
- __func__,
- rmi_fd.fn_number);
- return retval;
- }
-
- retval = synaptics_rmi4_f12_init(rmi4_data,
- fhandler, &rmi_fd, intr_count);
- if (retval < 0)
- return retval;
- break;
- case SYNAPTICS_RMI4_F1A:
- if (rmi_fd.intr_src_count == 0)
- break;
-
- retval = synaptics_rmi4_alloc_fh(&fhandler,
- &rmi_fd, page_number);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc for F%d\n",
- __func__,
- rmi_fd.fn_number);
- return retval;
- }
-
- retval = synaptics_rmi4_f1a_init(rmi4_data,
- fhandler, &rmi_fd, intr_count);
- if (retval < 0) {
-#ifdef IGNORE_FN_INIT_FAILURE
- kfree(fhandler);
- fhandler = NULL;
-#else
- return retval;
-#endif
- }
- break;
- case SYNAPTICS_RMI4_F35:
- f35found = true;
- break;
- }
-
- /* Accumulate the interrupt count */
- intr_count += rmi_fd.intr_src_count;
-
- if (fhandler && rmi_fd.intr_src_count) {
- list_add_tail(&fhandler->link,
- &rmi->support_fn_list);
- }
- }
- }
-
- if (!f01found) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to find F01\n",
- __func__);
- if (!f35found) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to find F35\n",
- __func__);
- return -EINVAL;
- } else {
- pr_notice("%s: In microbootloader mode\n",
- __func__);
- return 0;
- }
- }
-
-flash_prog_mode:
- rmi4_data->num_of_intr_regs = (intr_count + 7) / 8;
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Number of interrupt registers = %d\n",
- __func__, rmi4_data->num_of_intr_regs);
-
- f01_query = kmalloc(F01_STD_QUERY_LEN, GFP_KERNEL);
- if (!f01_query) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for f01_query\n",
- __func__);
- return -ENOMEM;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_query_base_addr,
- f01_query,
- F01_STD_QUERY_LEN);
- if (retval < 0) {
- kfree(f01_query);
- return retval;
- }
-
- /* RMI Version 4.0 currently supported */
- rmi->version_major = 4;
- rmi->version_minor = 0;
-
- rmi->manufacturer_id = f01_query[0];
- rmi->product_props = f01_query[1];
- rmi->product_info[0] = f01_query[2];
- rmi->product_info[1] = f01_query[3];
- retval = secure_memcpy(rmi->product_id_string,
- sizeof(rmi->product_id_string),
- &f01_query[11],
- F01_STD_QUERY_LEN - 11,
- PRODUCT_ID_SIZE);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy product ID string\n",
- __func__);
- }
-
- kfree(f01_query);
-
- if (rmi->manufacturer_id != 1) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Non-Synaptics device found, manufacturer ID = %d\n",
- __func__, rmi->manufacturer_id);
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_query_base_addr + F01_BUID_ID_OFFSET,
- rmi->build_id,
- sizeof(rmi->build_id));
- if (retval < 0)
- return retval;
-
- rmi4_data->firmware_id = (unsigned int)rmi->build_id[0] +
- (unsigned int)rmi->build_id[1] * 0x100 +
- (unsigned int)rmi->build_id[2] * 0x10000;
-
- memset(rmi4_data->intr_mask, 0x00, sizeof(rmi4_data->intr_mask));
-
- /*
- * Map out the interrupt bit masks for the interrupt sources
- * from the registered function handlers.
- */
- if (!list_empty(&rmi->support_fn_list)) {
- list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- if (fhandler->num_of_data_sources) {
- rmi4_data->intr_mask[fhandler->intr_reg_num] |=
- fhandler->intr_mask;
- }
- }
- }
-
- if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture)
- rmi4_data->enable_wakeup_gesture = WAKEUP_GESTURE;
- else
- rmi4_data->enable_wakeup_gesture = false;
-
- synaptics_rmi4_set_configured(rmi4_data);
-
- return 0;
-}
-
-static int synaptics_rmi4_gpio_setup(int gpio, bool config, int dir, int state)
-{
- int retval = 0;
- unsigned char buf[16];
-
- if (config) {
- retval = snprintf(buf, ARRAY_SIZE(buf), "dsx_gpio_%u\n", gpio);
- if (retval >= 16)
- return -EINVAL;
-
- retval = gpio_request(gpio, buf);
- if (retval) {
- pr_err("%s: Failed to get gpio %d (code: %d)",
- __func__, gpio, retval);
- return retval;
- }
-
- if (dir == 0)
- retval = gpio_direction_input(gpio);
- else
- retval = gpio_direction_output(gpio, state);
- if (retval) {
- pr_err("%s: Failed to set gpio %d direction",
- __func__, gpio);
- return retval;
- }
- } else {
- gpio_free(gpio);
- }
-
- return retval;
-}
-
-static void synaptics_rmi4_set_params(struct synaptics_rmi4_data *rmi4_data)
-{
- unsigned char ii;
- struct synaptics_rmi4_f1a_handle *f1a;
- struct synaptics_rmi4_fn *fhandler;
- struct synaptics_rmi4_device_info *rmi;
-
- rmi = &(rmi4_data->rmi4_mod_info);
-
- input_set_abs_params(rmi4_data->input_dev,
- ABS_MT_POSITION_X, 0,
- rmi4_data->sensor_max_x, 0, 0);
- input_set_abs_params(rmi4_data->input_dev,
- ABS_MT_POSITION_Y, 0,
- rmi4_data->sensor_max_y, 0, 0);
-#ifdef REPORT_2D_W
- input_set_abs_params(rmi4_data->input_dev,
- ABS_MT_TOUCH_MAJOR, 0,
- rmi4_data->max_touch_width, 0, 0);
- input_set_abs_params(rmi4_data->input_dev,
- ABS_MT_TOUCH_MINOR, 0,
- rmi4_data->max_touch_width, 0, 0);
-#endif
-
-#ifdef REPORT_2D_PRESSURE
- if (rmi4_data->report_pressure) {
- input_set_abs_params(rmi4_data->input_dev,
- ABS_MT_PRESSURE, 0,
- MAX_F12_TOUCH_PRESSURE, 0, 0);
- }
-#endif
-
-#ifdef TYPE_B_PROTOCOL
-#ifdef KERNEL_ABOVE_3_6
- input_mt_init_slots(rmi4_data->input_dev,
- rmi4_data->num_of_fingers, INPUT_MT_DIRECT);
-#else
- input_mt_init_slots(rmi4_data->input_dev,
- rmi4_data->num_of_fingers);
-#endif
-#endif
-
- f1a = NULL;
- if (!list_empty(&rmi->support_fn_list)) {
- list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
- f1a = fhandler->data;
- }
- }
-
- if (f1a) {
- for (ii = 0; ii < f1a->valid_button_count; ii++) {
- set_bit(f1a->button_map[ii],
- rmi4_data->input_dev->keybit);
- input_set_capability(rmi4_data->input_dev,
- EV_KEY, f1a->button_map[ii]);
- }
- }
-
- if (vir_button_map->nbuttons) {
- for (ii = 0; ii < vir_button_map->nbuttons; ii++) {
- set_bit(vir_button_map->map[ii * 5],
- rmi4_data->input_dev->keybit);
- input_set_capability(rmi4_data->input_dev,
- EV_KEY, vir_button_map->map[ii * 5]);
- }
- }
-
- if (rmi4_data->f11_wakeup_gesture || rmi4_data->f12_wakeup_gesture) {
- set_bit(KEY_WAKEUP, rmi4_data->input_dev->keybit);
- input_set_capability(rmi4_data->input_dev, EV_KEY, KEY_WAKEUP);
- }
-
- return;
-}
-
-static int synaptics_rmi4_set_input_dev(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- rmi4_data->input_dev = input_allocate_device();
- if (rmi4_data->input_dev == NULL) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to allocate input device\n",
- __func__);
- retval = -ENOMEM;
- goto err_input_device;
- }
-
- retval = synaptics_rmi4_query_device(rmi4_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to query device\n",
- __func__);
- goto err_query_device;
- }
-
- rmi4_data->input_dev->name = PLATFORM_DRIVER_NAME;
- rmi4_data->input_dev->phys = INPUT_PHYS_NAME;
- rmi4_data->input_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
- rmi4_data->input_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
- rmi4_data->input_dev->dev.parent = rmi4_data->pdev->dev.parent;
- input_set_drvdata(rmi4_data->input_dev, rmi4_data);
-
- set_bit(EV_SYN, rmi4_data->input_dev->evbit);
- set_bit(EV_KEY, rmi4_data->input_dev->evbit);
- set_bit(EV_ABS, rmi4_data->input_dev->evbit);
- set_bit(BTN_TOUCH, rmi4_data->input_dev->keybit);
- set_bit(BTN_TOOL_FINGER, rmi4_data->input_dev->keybit);
-#ifdef INPUT_PROP_DIRECT
- set_bit(INPUT_PROP_DIRECT, rmi4_data->input_dev->propbit);
-#endif
-
- if (bdata->max_y_for_2d >= 0)
- rmi4_data->sensor_max_y = bdata->max_y_for_2d;
-
- synaptics_rmi4_set_params(rmi4_data);
-
- retval = input_register_device(rmi4_data->input_dev);
- if (retval) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to register input device\n",
- __func__);
- goto err_register_input;
- }
-
- if (!rmi4_data->stylus_enable)
- return 0;
-
- rmi4_data->stylus_dev = input_allocate_device();
- if (rmi4_data->stylus_dev == NULL) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to allocate stylus device\n",
- __func__);
- retval = -ENOMEM;
- goto err_stylus_device;
- }
-
- rmi4_data->stylus_dev->name = STYLUS_DRIVER_NAME;
- rmi4_data->stylus_dev->phys = STYLUS_PHYS_NAME;
- rmi4_data->stylus_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
- rmi4_data->stylus_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
- rmi4_data->stylus_dev->dev.parent = rmi4_data->pdev->dev.parent;
- input_set_drvdata(rmi4_data->stylus_dev, rmi4_data);
-
- set_bit(EV_KEY, rmi4_data->stylus_dev->evbit);
- set_bit(EV_ABS, rmi4_data->stylus_dev->evbit);
- set_bit(BTN_TOUCH, rmi4_data->stylus_dev->keybit);
- set_bit(BTN_TOOL_PEN, rmi4_data->stylus_dev->keybit);
- if (rmi4_data->eraser_enable)
- set_bit(BTN_TOOL_RUBBER, rmi4_data->stylus_dev->keybit);
-#ifdef INPUT_PROP_DIRECT
- set_bit(INPUT_PROP_DIRECT, rmi4_data->stylus_dev->propbit);
-#endif
-
- input_set_abs_params(rmi4_data->stylus_dev, ABS_X, 0,
- rmi4_data->sensor_max_x, 0, 0);
- input_set_abs_params(rmi4_data->stylus_dev, ABS_Y, 0,
- rmi4_data->sensor_max_y, 0, 0);
-
- retval = input_register_device(rmi4_data->stylus_dev);
- if (retval) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to register stylus device\n",
- __func__);
- goto err_register_stylus;
- }
-
- return 0;
-
-err_register_stylus:
- rmi4_data->stylus_dev = NULL;
-
-err_stylus_device:
- input_unregister_device(rmi4_data->input_dev);
- rmi4_data->input_dev = NULL;
-
-err_register_input:
-err_query_device:
- synaptics_rmi4_empty_fn_list(rmi4_data);
- input_free_device(rmi4_data->input_dev);
-
-err_input_device:
- return retval;
-}
-
-static int synaptics_rmi4_set_gpio(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- retval = synaptics_rmi4_gpio_setup(
- bdata->irq_gpio,
- true, 0, 0);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to configure attention GPIO\n",
- __func__);
- goto err_gpio_irq;
- }
-
- if (bdata->power_gpio >= 0) {
- retval = synaptics_rmi4_gpio_setup(
- bdata->power_gpio,
- true, 1, !bdata->power_on_state);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to configure power GPIO\n",
- __func__);
- goto err_gpio_power;
- }
- }
-
- if (bdata->reset_gpio >= 0) {
- retval = synaptics_rmi4_gpio_setup(
- bdata->reset_gpio,
- true, 1, !bdata->reset_on_state);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to configure reset GPIO\n",
- __func__);
- goto err_gpio_reset;
- }
- }
-
- if (bdata->power_gpio >= 0) {
- gpio_set_value(bdata->power_gpio, bdata->power_on_state);
- msleep(bdata->power_delay_ms);
- }
-
- if (bdata->reset_gpio >= 0) {
- gpio_set_value(bdata->reset_gpio, bdata->reset_on_state);
- msleep(bdata->reset_active_ms);
- gpio_set_value(bdata->reset_gpio, !bdata->reset_on_state);
- msleep(bdata->reset_delay_ms);
- }
-
- return 0;
-
-err_gpio_reset:
- if (bdata->power_gpio >= 0)
- synaptics_rmi4_gpio_setup(bdata->power_gpio, false, 0, 0);
-
-err_gpio_power:
- synaptics_rmi4_gpio_setup(bdata->irq_gpio, false, 0, 0);
-
-err_gpio_irq:
- return retval;
-}
-
-static int synaptics_rmi4_get_reg(struct synaptics_rmi4_data *rmi4_data,
- bool get)
-{
- int retval;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- if (!get) {
- retval = 0;
- goto regulator_put;
- }
-
- if ((bdata->pwr_reg_name != NULL) && (*bdata->pwr_reg_name != 0)) {
- rmi4_data->pwr_reg = regulator_get(rmi4_data->pdev->dev.parent,
- bdata->pwr_reg_name);
- if (IS_ERR(rmi4_data->pwr_reg)) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to get power regulator\n",
- __func__);
- retval = PTR_ERR(rmi4_data->pwr_reg);
- goto regulator_put;
- }
- }
-
- if ((bdata->bus_reg_name != NULL) && (*bdata->bus_reg_name != 0)) {
- rmi4_data->bus_reg = regulator_get(rmi4_data->pdev->dev.parent,
- bdata->bus_reg_name);
- if (IS_ERR(rmi4_data->bus_reg)) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to get bus pullup regulator\n",
- __func__);
- retval = PTR_ERR(rmi4_data->bus_reg);
- goto regulator_put;
- }
- }
-
- return 0;
-
-regulator_put:
- if (rmi4_data->pwr_reg) {
- regulator_put(rmi4_data->pwr_reg);
- rmi4_data->pwr_reg = NULL;
- }
-
- if (rmi4_data->bus_reg) {
- regulator_put(rmi4_data->bus_reg);
- rmi4_data->bus_reg = NULL;
- }
-
- return retval;
-}
-
-static int synaptics_rmi4_enable_reg(struct synaptics_rmi4_data *rmi4_data,
- bool enable)
-{
- int retval;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- if (!enable) {
- retval = 0;
- goto disable_pwr_reg;
- }
-
- if (rmi4_data->bus_reg) {
- retval = regulator_enable(rmi4_data->bus_reg);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to enable bus pullup regulator\n",
- __func__);
- goto exit;
- }
- }
-
- if (rmi4_data->pwr_reg) {
- retval = regulator_enable(rmi4_data->pwr_reg);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to enable power regulator\n",
- __func__);
- goto disable_bus_reg;
- }
- msleep(bdata->power_delay_ms);
- }
-
- return 0;
-
-disable_pwr_reg:
- if (rmi4_data->pwr_reg)
- regulator_disable(rmi4_data->pwr_reg);
-
-disable_bus_reg:
- if (rmi4_data->bus_reg)
- regulator_disable(rmi4_data->bus_reg);
-
-exit:
- return retval;
-}
-
-static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data)
-{
- unsigned char ii;
-
- mutex_lock(&(rmi4_data->rmi4_report_mutex));
-
-#ifdef TYPE_B_PROTOCOL
- for (ii = 0; ii < rmi4_data->num_of_fingers; ii++) {
- input_mt_slot(rmi4_data->input_dev, ii);
- input_mt_report_slot_state(rmi4_data->input_dev,
- MT_TOOL_FINGER, 0);
- }
-#endif
- input_report_key(rmi4_data->input_dev,
- BTN_TOUCH, 0);
- input_report_key(rmi4_data->input_dev,
- BTN_TOOL_FINGER, 0);
-#ifndef TYPE_B_PROTOCOL
- input_mt_sync(rmi4_data->input_dev);
-#endif
- input_sync(rmi4_data->input_dev);
-
- if (rmi4_data->stylus_enable) {
- input_report_key(rmi4_data->stylus_dev,
- BTN_TOUCH, 0);
- input_report_key(rmi4_data->stylus_dev,
- BTN_TOOL_PEN, 0);
- if (rmi4_data->eraser_enable) {
- input_report_key(rmi4_data->stylus_dev,
- BTN_TOOL_RUBBER, 0);
- }
- input_sync(rmi4_data->stylus_dev);
- }
-
- mutex_unlock(&(rmi4_data->rmi4_report_mutex));
-
- rmi4_data->fingers_on_2d = false;
-
- return 0;
-}
-
-static int synaptics_rmi4_sw_reset(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- unsigned char command = 0x01;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- rmi4_data->f01_cmd_base_addr,
- &command,
- sizeof(command));
- if (retval < 0)
- return retval;
-
- msleep(rmi4_data->hw_if->board_data->reset_delay_ms);
-
- if (rmi4_data->hw_if->ui_hw_init) {
- retval = rmi4_data->hw_if->ui_hw_init(rmi4_data);
- if (retval < 0)
- return retval;
- }
-
- return 0;
-}
-
-static void synaptics_rmi4_rebuild_work(struct work_struct *work)
-{
- int retval;
- unsigned char attr_count;
- struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- struct delayed_work *delayed_work =
- container_of(work, struct delayed_work, work);
- struct synaptics_rmi4_data *rmi4_data =
- container_of(delayed_work, struct synaptics_rmi4_data,
- rb_work);
-
- mutex_lock(&(rmi4_data->rmi4_reset_mutex));
-
- mutex_lock(&exp_data.mutex);
-
- synaptics_rmi4_irq_enable(rmi4_data, false, false);
-
- if (!list_empty(&exp_data.list)) {
- list_for_each_entry(exp_fhandler, &exp_data.list, link)
- if (exp_fhandler->exp_fn->remove != NULL)
- exp_fhandler->exp_fn->remove(rmi4_data);
- }
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- }
-
- synaptics_rmi4_free_fingers(rmi4_data);
- synaptics_rmi4_empty_fn_list(rmi4_data);
- input_unregister_device(rmi4_data->input_dev);
- rmi4_data->input_dev = NULL;
- if (rmi4_data->stylus_enable) {
- input_unregister_device(rmi4_data->stylus_dev);
- rmi4_data->stylus_dev = NULL;
- }
-
- retval = synaptics_rmi4_sw_reset(rmi4_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to issue reset command\n",
- __func__);
- goto exit;
- }
-
- retval = synaptics_rmi4_set_input_dev(rmi4_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set up input device\n",
- __func__);
- goto exit;
- }
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs attributes\n",
- __func__);
- goto exit;
- }
- }
-
- if (!list_empty(&exp_data.list)) {
- list_for_each_entry(exp_fhandler, &exp_data.list, link)
- if (exp_fhandler->exp_fn->init != NULL)
- exp_fhandler->exp_fn->init(rmi4_data);
- }
-
- retval = 0;
-
-exit:
- synaptics_rmi4_irq_enable(rmi4_data, true, false);
-
- mutex_unlock(&exp_data.mutex);
-
- mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
-
- return;
-}
-
-static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data,
- bool rebuild)
-{
- int retval;
- struct synaptics_rmi4_exp_fhandler *exp_fhandler;
-
- if (rebuild) {
- queue_delayed_work(rmi4_data->rb_workqueue,
- &rmi4_data->rb_work,
- msecs_to_jiffies(REBUILD_WORK_DELAY_MS));
- return 0;
- }
-
- mutex_lock(&(rmi4_data->rmi4_reset_mutex));
-
- synaptics_rmi4_irq_enable(rmi4_data, false, false);
-
- retval = synaptics_rmi4_sw_reset(rmi4_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to issue reset command\n",
- __func__);
- goto exit;
- }
-
- synaptics_rmi4_free_fingers(rmi4_data);
-
- synaptics_rmi4_empty_fn_list(rmi4_data);
-
- retval = synaptics_rmi4_query_device(rmi4_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to query device\n",
- __func__);
- goto exit;
- }
-
- mutex_lock(&exp_data.mutex);
- if (!list_empty(&exp_data.list)) {
- list_for_each_entry(exp_fhandler, &exp_data.list, link)
- if (exp_fhandler->exp_fn->reset != NULL)
- exp_fhandler->exp_fn->reset(rmi4_data);
- }
- mutex_unlock(&exp_data.mutex);
-
- retval = 0;
-
-exit:
- synaptics_rmi4_irq_enable(rmi4_data, true, false);
-
- mutex_unlock(&(rmi4_data->rmi4_reset_mutex));
-
- return retval;
-}
-
-#ifdef FB_READY_RESET
-static void synaptics_rmi4_reset_work(struct work_struct *work)
-{
- int retval;
- unsigned int timeout;
- struct synaptics_rmi4_data *rmi4_data =
- container_of(work, struct synaptics_rmi4_data,
- reset_work);
-
- timeout = FB_READY_TIMEOUT_S * 1000 / FB_READY_WAIT_MS + 1;
-
- while (!rmi4_data->fb_ready) {
- msleep(FB_READY_WAIT_MS);
- timeout--;
- if (timeout == 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Timed out waiting for FB ready\n",
- __func__);
- return;
- }
- }
-
- mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
-
- retval = synaptics_rmi4_reset_device(rmi4_data, false);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to issue reset command\n",
- __func__);
- }
-
- mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
-
- return;
-}
-#endif
-
-static void synaptics_rmi4_sleep_enable(struct synaptics_rmi4_data *rmi4_data,
- bool enable)
-{
- int retval;
- unsigned char device_ctrl;
- unsigned char no_sleep_setting = rmi4_data->no_sleep_setting;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_ctrl_base_addr,
- &device_ctrl,
- sizeof(device_ctrl));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read device control\n",
- __func__);
- return;
- }
-
- device_ctrl = device_ctrl & ~MASK_3BIT;
- if (enable)
- device_ctrl = device_ctrl | NO_SLEEP_OFF | SENSOR_SLEEP;
- else
- device_ctrl = device_ctrl | no_sleep_setting | NORMAL_OPERATION;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- rmi4_data->f01_ctrl_base_addr,
- &device_ctrl,
- sizeof(device_ctrl));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write device control\n",
- __func__);
- return;
- }
-
- rmi4_data->sensor_sleep = enable;
-
- return;
-}
-
-static void synaptics_rmi4_exp_fn_work(struct work_struct *work)
-{
- struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- struct synaptics_rmi4_exp_fhandler *exp_fhandler_temp;
- struct synaptics_rmi4_data *rmi4_data = exp_data.rmi4_data;
-
- mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
- mutex_lock(&rmi4_data->rmi4_reset_mutex);
- mutex_lock(&exp_data.mutex);
- if (!list_empty(&exp_data.list)) {
- list_for_each_entry_safe(exp_fhandler,
- exp_fhandler_temp,
- &exp_data.list,
- link) {
- if ((exp_fhandler->exp_fn->init != NULL) &&
- exp_fhandler->insert) {
- exp_fhandler->exp_fn->init(rmi4_data);
- exp_fhandler->insert = false;
- } else if ((exp_fhandler->exp_fn->remove != NULL) &&
- exp_fhandler->remove) {
- exp_fhandler->exp_fn->remove(rmi4_data);
- list_del(&exp_fhandler->link);
- kfree(exp_fhandler);
- }
- }
- }
- mutex_unlock(&exp_data.mutex);
- mutex_unlock(&rmi4_data->rmi4_reset_mutex);
- mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
-
- return;
-}
-
-void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn,
- bool insert)
-{
- struct synaptics_rmi4_exp_fhandler *exp_fhandler;
-
- if (!exp_data.initialized) {
- mutex_init(&exp_data.mutex);
- INIT_LIST_HEAD(&exp_data.list);
- exp_data.initialized = true;
- }
-
- mutex_lock(&exp_data.mutex);
- if (insert) {
- exp_fhandler = kzalloc(sizeof(*exp_fhandler), GFP_KERNEL);
- if (!exp_fhandler) {
- pr_err("%s: Failed to alloc mem for expansion function\n",
- __func__);
- goto exit;
- }
- exp_fhandler->exp_fn = exp_fn;
- exp_fhandler->insert = true;
- exp_fhandler->remove = false;
- list_add_tail(&exp_fhandler->link, &exp_data.list);
- } else if (!list_empty(&exp_data.list)) {
- list_for_each_entry(exp_fhandler, &exp_data.list, link) {
- if (exp_fhandler->exp_fn->fn_type == exp_fn->fn_type) {
- exp_fhandler->insert = false;
- exp_fhandler->remove = true;
- goto exit;
- }
- }
- }
-
-exit:
- mutex_unlock(&exp_data.mutex);
-
- if (exp_data.queue_work) {
- queue_delayed_work(exp_data.workqueue,
- &exp_data.work,
- msecs_to_jiffies(EXP_FN_WORK_DELAY_MS));
- }
-
- return;
-}
-EXPORT_SYMBOL(synaptics_rmi4_new_function);
-
-static int synaptics_dsx_pinctrl_init(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
-
- /* Get pinctrl if target uses pinctrl */
- rmi4_data->ts_pinctrl = devm_pinctrl_get((rmi4_data->pdev->dev.parent));
- if (IS_ERR_OR_NULL(rmi4_data->ts_pinctrl)) {
- retval = PTR_ERR(rmi4_data->ts_pinctrl);
- dev_err(rmi4_data->pdev->dev.parent,
- "Target does not use pinctrl %d\n", retval);
- goto err_pinctrl_get;
- }
-
- rmi4_data->pinctrl_state_active
- = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_active");
- if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_active)) {
- retval = PTR_ERR(rmi4_data->pinctrl_state_active);
- dev_err(rmi4_data->pdev->dev.parent,
- "Can not lookup %s pinstate %d\n",
- PINCTRL_STATE_ACTIVE, retval);
- goto err_pinctrl_lookup;
- }
-
- rmi4_data->pinctrl_state_suspend
- = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_suspend");
- if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_suspend)) {
- retval = PTR_ERR(rmi4_data->pinctrl_state_suspend);
- dev_dbg(rmi4_data->pdev->dev.parent,
- "Can not lookup %s pinstate %d\n",
- PINCTRL_STATE_SUSPEND, retval);
- goto err_pinctrl_lookup;
- }
-
- rmi4_data->pinctrl_state_release
- = pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_release");
- if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
- retval = PTR_ERR(rmi4_data->pinctrl_state_release);
- dev_dbg(rmi4_data->pdev->dev.parent,
- "Can not lookup %s pinstate %d\n",
- PINCTRL_STATE_RELEASE, retval);
- }
-
- return 0;
-
-err_pinctrl_lookup:
- devm_pinctrl_put(rmi4_data->ts_pinctrl);
-err_pinctrl_get:
- rmi4_data->ts_pinctrl = NULL;
- return retval;
-}
-
-static int synaptics_rmi4_probe(struct platform_device *pdev)
-{
- int retval;
- unsigned char attr_count;
- struct synaptics_rmi4_data *rmi4_data;
- const struct synaptics_dsx_hw_interface *hw_if;
- const struct synaptics_dsx_board_data *bdata;
-
- hw_if = pdev->dev.platform_data;
- if (!hw_if) {
- dev_err(&pdev->dev,
- "%s: No hardware interface found\n",
- __func__);
- return -EINVAL;
- }
-
- bdata = hw_if->board_data;
- if (!bdata) {
- dev_err(&pdev->dev,
- "%s: No board data found\n",
- __func__);
- return -EINVAL;
- }
-
- rmi4_data = kzalloc(sizeof(*rmi4_data), GFP_KERNEL);
- if (!rmi4_data) {
- dev_err(&pdev->dev,
- "%s: Failed to alloc mem for rmi4_data\n",
- __func__);
- return -ENOMEM;
- }
-
- rmi4_data->pdev = pdev;
- rmi4_data->current_page = MASK_8BIT;
- rmi4_data->hw_if = hw_if;
- rmi4_data->suspend = false;
- rmi4_data->irq_enabled = false;
- rmi4_data->fingers_on_2d = false;
-
- rmi4_data->reset_device = synaptics_rmi4_reset_device;
- rmi4_data->irq_enable = synaptics_rmi4_irq_enable;
- rmi4_data->sleep_enable = synaptics_rmi4_sleep_enable;
- rmi4_data->report_touch = synaptics_rmi4_report_touch;
-
- mutex_init(&(rmi4_data->rmi4_reset_mutex));
- mutex_init(&(rmi4_data->rmi4_report_mutex));
- mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
- mutex_init(&(rmi4_data->rmi4_exp_init_mutex));
-
- platform_set_drvdata(pdev, rmi4_data);
-
- vir_button_map = bdata->vir_button_map;
-
- retval = synaptics_rmi4_get_reg(rmi4_data, true);
- if (retval < 0) {
- dev_err(&pdev->dev,
- "%s: Failed to get regulators\n",
- __func__);
- goto err_get_reg;
- }
-
- retval = synaptics_rmi4_enable_reg(rmi4_data, true);
- if (retval < 0) {
- dev_err(&pdev->dev,
- "%s: Failed to enable regulators\n",
- __func__);
- goto err_enable_reg;
- }
-
- retval = synaptics_dsx_pinctrl_init(rmi4_data);
- if (!retval && rmi4_data->ts_pinctrl) {
- /*
- * Pinctrl handle is optional. If pinctrl handle is found
- * let pins to be configured in active state. If not
- * found continue further without error.
- */
- retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
- rmi4_data->pinctrl_state_active);
- if (retval < 0) {
- dev_err(&pdev->dev,
- "%s: Failed to select %s pinstate %d\n",
- __func__, PINCTRL_STATE_ACTIVE, retval);
- }
- }
- retval = synaptics_rmi4_set_gpio(rmi4_data);
- if (retval < 0) {
- dev_err(&pdev->dev,
- "%s: Failed to set up GPIO's\n",
- __func__);
- goto err_set_gpio;
- }
-
- if (hw_if->ui_hw_init) {
- retval = hw_if->ui_hw_init(rmi4_data);
- if (retval < 0) {
- dev_err(&pdev->dev,
- "%s: Failed to initialize hardware interface\n",
- __func__);
- goto err_ui_hw_init;
- }
- }
-
- retval = synaptics_rmi4_set_input_dev(rmi4_data);
- if (retval < 0) {
- dev_err(&pdev->dev,
- "%s: Failed to set up input device\n",
- __func__);
- goto err_set_input_dev;
- }
-
-#ifdef CONFIG_FB
- INIT_WORK(&rmi4_data->fb_notify_work,
- synaptics_rmi4_fb_notify_resume_work);
- rmi4_data->fb_notifier.notifier_call = synaptics_rmi4_fb_notifier_cb;
- retval = fb_register_client(&rmi4_data->fb_notifier);
- if (retval < 0) {
- dev_err(&pdev->dev,
- "%s: Failed to register fb notifier client\n",
- __func__);
- }
-#endif
-
-#ifdef USE_EARLYSUSPEND
- rmi4_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
- rmi4_data->early_suspend.suspend = synaptics_rmi4_early_suspend;
- rmi4_data->early_suspend.resume = synaptics_rmi4_late_resume;
- register_early_suspend(&rmi4_data->early_suspend);
-#endif
-
- if (!exp_data.initialized) {
- mutex_init(&exp_data.mutex);
- INIT_LIST_HEAD(&exp_data.list);
- exp_data.initialized = true;
- }
-
- rmi4_data->irq = gpio_to_irq(bdata->irq_gpio);
-
- retval = synaptics_rmi4_irq_enable(rmi4_data, true, false);
- if (retval < 0) {
- dev_err(&pdev->dev,
- "%s: Failed to enable attention interrupt\n",
- __func__);
- goto err_enable_irq;
- }
-
- if (vir_button_map->nbuttons) {
- rmi4_data->board_prop_dir = kobject_create_and_add(
- "board_properties", NULL);
- if (!rmi4_data->board_prop_dir) {
- dev_err(&pdev->dev,
- "%s: Failed to create board_properties directory\n",
- __func__);
- goto err_virtual_buttons;
- } else {
- retval = sysfs_create_file(rmi4_data->board_prop_dir,
- &virtual_key_map_attr.attr);
- if (retval < 0) {
- dev_err(&pdev->dev,
- "%s: Failed to create virtual key map file\n",
- __func__);
- goto err_virtual_buttons;
- }
- }
- }
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- if (retval < 0) {
- dev_err(&pdev->dev,
- "%s: Failed to create sysfs attributes\n",
- __func__);
- goto err_sysfs;
- }
- }
-
- rmi4_data->rb_workqueue =
- create_singlethread_workqueue("dsx_rebuild_workqueue");
- if (!rmi4_data->rb_workqueue) {
- retval = -ENOMEM;
- goto err_rb_workqueue;
- }
- INIT_DELAYED_WORK(&rmi4_data->rb_work, synaptics_rmi4_rebuild_work);
-
- exp_data.workqueue = create_singlethread_workqueue("dsx_exp_workqueue");
- if (!exp_data.workqueue) {
- retval = -ENOMEM;
- goto err_exp_data_workqueue;
- }
- INIT_DELAYED_WORK(&exp_data.work, synaptics_rmi4_exp_fn_work);
- exp_data.rmi4_data = rmi4_data;
- exp_data.queue_work = true;
- queue_delayed_work(exp_data.workqueue, &exp_data.work, 0);
-
-#ifdef FB_READY_RESET
- rmi4_data->reset_workqueue =
- create_singlethread_workqueue("dsx_reset_workqueue");
- if (!rmi4_data->reset_workqueue) {
- retval = -ENOMEM;
- goto err_reset_workqueue;
- }
- INIT_WORK(&rmi4_data->reset_work, synaptics_rmi4_reset_work);
- queue_work(rmi4_data->reset_workqueue, &rmi4_data->reset_work);
-#endif
-
- /* Initialize secure touch */
- synaptics_secure_touch_init(rmi4_data);
- synaptics_secure_touch_stop(rmi4_data, true);
-
- return retval;
-
-#ifdef FB_READY_RESET
-err_reset_workqueue:
-#endif
- cancel_delayed_work_sync(&exp_data.work);
- flush_workqueue(exp_data.workqueue);
- destroy_workqueue(exp_data.workqueue);
-
-err_exp_data_workqueue:
- cancel_delayed_work_sync(&rmi4_data->rb_work);
- flush_workqueue(rmi4_data->rb_workqueue);
- destroy_workqueue(rmi4_data->rb_workqueue);
-
-err_rb_workqueue:
-err_sysfs:
- for (attr_count--; attr_count >= 0; attr_count--) {
- sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- }
-
-err_virtual_buttons:
- if (rmi4_data->board_prop_dir) {
- sysfs_remove_file(rmi4_data->board_prop_dir,
- &virtual_key_map_attr.attr);
- kobject_put(rmi4_data->board_prop_dir);
- }
-
- synaptics_rmi4_irq_enable(rmi4_data, false, false);
-
-err_enable_irq:
-#ifdef CONFIG_FB
- fb_unregister_client(&rmi4_data->fb_notifier);
-#endif
-
-#ifdef USE_EARLYSUSPEND
- unregister_early_suspend(&rmi4_data->early_suspend);
-#endif
-
- synaptics_rmi4_empty_fn_list(rmi4_data);
- input_unregister_device(rmi4_data->input_dev);
- rmi4_data->input_dev = NULL;
- if (rmi4_data->stylus_enable) {
- input_unregister_device(rmi4_data->stylus_dev);
- rmi4_data->stylus_dev = NULL;
- }
-
-err_set_input_dev:
- synaptics_rmi4_gpio_setup(bdata->irq_gpio, false, 0, 0);
-
- if (bdata->reset_gpio >= 0)
- synaptics_rmi4_gpio_setup(bdata->reset_gpio, false, 0, 0);
-
- if (bdata->power_gpio >= 0)
- synaptics_rmi4_gpio_setup(bdata->power_gpio, false, 0, 0);
-
-err_ui_hw_init:
-err_set_gpio:
- synaptics_rmi4_enable_reg(rmi4_data, false);
-
- if (rmi4_data->ts_pinctrl) {
- if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
- devm_pinctrl_put(rmi4_data->ts_pinctrl);
- rmi4_data->ts_pinctrl = NULL;
- } else {
- retval = pinctrl_select_state(
- rmi4_data->ts_pinctrl,
- rmi4_data->pinctrl_state_release);
- if (retval)
- dev_err(&pdev->dev,
- "%s: Failed to create sysfs attributes\n",
- __func__);
- }
- }
-
-err_enable_reg:
- synaptics_rmi4_get_reg(rmi4_data, false);
-
-err_get_reg:
- kfree(rmi4_data);
-
- return retval;
-}
-
-static int synaptics_rmi4_remove(struct platform_device *pdev)
-{
- unsigned char attr_count;
- int err;
- struct synaptics_rmi4_data *rmi4_data = platform_get_drvdata(pdev);
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
-#ifdef FB_READY_RESET
- cancel_work_sync(&rmi4_data->reset_work);
- flush_workqueue(rmi4_data->reset_workqueue);
- destroy_workqueue(rmi4_data->reset_workqueue);
-#endif
-
- cancel_delayed_work_sync(&exp_data.work);
- flush_workqueue(exp_data.workqueue);
- destroy_workqueue(exp_data.workqueue);
-
- cancel_delayed_work_sync(&rmi4_data->rb_work);
- flush_workqueue(rmi4_data->rb_workqueue);
- destroy_workqueue(rmi4_data->rb_workqueue);
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- }
-
- if (rmi4_data->board_prop_dir) {
- sysfs_remove_file(rmi4_data->board_prop_dir,
- &virtual_key_map_attr.attr);
- kobject_put(rmi4_data->board_prop_dir);
- }
-
- synaptics_rmi4_irq_enable(rmi4_data, false, false);
-
-#ifdef CONFIG_FB
- fb_unregister_client(&rmi4_data->fb_notifier);
-#endif
-
-#ifdef USE_EARLYSUSPEND
- unregister_early_suspend(&rmi4_data->early_suspend);
-#endif
-
- synaptics_rmi4_empty_fn_list(rmi4_data);
- input_unregister_device(rmi4_data->input_dev);
- rmi4_data->input_dev = NULL;
- if (rmi4_data->stylus_enable) {
- input_unregister_device(rmi4_data->stylus_dev);
- rmi4_data->stylus_dev = NULL;
- }
-
- synaptics_rmi4_gpio_setup(bdata->irq_gpio, false, 0, 0);
-
- if (bdata->reset_gpio >= 0)
- synaptics_rmi4_gpio_setup(bdata->reset_gpio, false, 0, 0);
-
- if (bdata->power_gpio >= 0)
- synaptics_rmi4_gpio_setup(bdata->power_gpio, false, 0, 0);
-
-
- if (rmi4_data->ts_pinctrl) {
- if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
- devm_pinctrl_put(rmi4_data->ts_pinctrl);
- rmi4_data->ts_pinctrl = NULL;
- } else {
- err = pinctrl_select_state(
- rmi4_data->ts_pinctrl,
- rmi4_data->pinctrl_state_release);
- if (err)
- dev_err(&pdev->dev,
- "Failed to select release pinctrl state %d\n",
- err);
- }
- }
-
- synaptics_rmi4_enable_reg(rmi4_data, false);
- synaptics_rmi4_get_reg(rmi4_data, false);
-
- kfree(rmi4_data);
-
- return 0;
-}
-
-static void synaptics_rmi4_f11_wg(struct synaptics_rmi4_data *rmi4_data,
- bool enable)
-{
- int retval;
- unsigned char reporting_control;
- struct synaptics_rmi4_fn *fhandler;
- struct synaptics_rmi4_device_info *rmi;
-
- rmi = &(rmi4_data->rmi4_mod_info);
-
- list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- if (fhandler->fn_number == SYNAPTICS_RMI4_F11)
- break;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.ctrl_base,
- &reporting_control,
- sizeof(reporting_control));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to change reporting mode\n",
- __func__);
- return;
- }
-
- reporting_control = (reporting_control & ~MASK_3BIT);
- if (enable)
- reporting_control |= F11_WAKEUP_GESTURE_MODE;
- else
- reporting_control |= F11_CONTINUOUS_MODE;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- fhandler->full_addr.ctrl_base,
- &reporting_control,
- sizeof(reporting_control));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to change reporting mode\n",
- __func__);
- return;
- }
-
- return;
-}
-
-static void synaptics_rmi4_f12_wg(struct synaptics_rmi4_data *rmi4_data,
- bool enable)
-{
- int retval;
- unsigned char offset;
- unsigned char reporting_control[3];
- struct synaptics_rmi4_f12_extra_data *extra_data;
- struct synaptics_rmi4_fn *fhandler;
- struct synaptics_rmi4_device_info *rmi;
-
- rmi = &(rmi4_data->rmi4_mod_info);
-
- list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- if (fhandler->fn_number == SYNAPTICS_RMI4_F12)
- break;
- }
-
- extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra;
- offset = extra_data->ctrl20_offset;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fhandler->full_addr.ctrl_base + offset,
- reporting_control,
- sizeof(reporting_control));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to change reporting mode\n",
- __func__);
- return;
- }
-
- if (enable)
- reporting_control[2] = F12_WAKEUP_GESTURE_MODE;
- else
- reporting_control[2] = F12_CONTINUOUS_MODE;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- fhandler->full_addr.ctrl_base + offset,
- reporting_control,
- sizeof(reporting_control));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to change reporting mode\n",
- __func__);
- return;
- }
-
- return;
-}
-
-static void synaptics_rmi4_wakeup_gesture(struct synaptics_rmi4_data *rmi4_data,
- bool enable)
-{
- if (rmi4_data->f11_wakeup_gesture)
- synaptics_rmi4_f11_wg(rmi4_data, enable);
- else if (rmi4_data->f12_wakeup_gesture)
- synaptics_rmi4_f12_wg(rmi4_data, enable);
-
- return;
-}
-
-#ifdef CONFIG_FB
-static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work)
-{
- struct synaptics_rmi4_data *rmi4_data =
- container_of(work, struct synaptics_rmi4_data, fb_notify_work);
- synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
- rmi4_data->fb_ready = true;
-}
-
-static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self,
- unsigned long event, void *data)
-{
- int *transition;
- struct fb_event *evdata = data;
- struct synaptics_rmi4_data *rmi4_data =
- container_of(self, struct synaptics_rmi4_data,
- fb_notifier);
-
- if (evdata && evdata->data && rmi4_data) {
- if (rmi4_data->hw_if->board_data->resume_in_workqueue) {
- if (event == FB_EARLY_EVENT_BLANK) {
- synaptics_secure_touch_stop(rmi4_data, false);
- } else if (event == FB_EVENT_BLANK) {
- transition = evdata->data;
- if (*transition == FB_BLANK_POWERDOWN) {
- flush_work(
- &(rmi4_data->fb_notify_work));
- synaptics_rmi4_suspend(
- &rmi4_data->pdev->dev);
- rmi4_data->fb_ready = false;
- } else if (*transition == FB_BLANK_UNBLANK) {
- schedule_work(
- &(rmi4_data->fb_notify_work));
- }
- }
- } else {
- if (event == FB_EARLY_EVENT_BLANK) {
- synaptics_secure_touch_stop(rmi4_data, false);
- } else if (event == FB_EVENT_BLANK) {
- transition = evdata->data;
- if (*transition == FB_BLANK_POWERDOWN) {
- synaptics_rmi4_suspend(
- &rmi4_data->pdev->dev);
- rmi4_data->fb_ready = false;
- } else if (*transition == FB_BLANK_UNBLANK) {
- synaptics_rmi4_resume(
- &rmi4_data->pdev->dev);
- rmi4_data->fb_ready = true;
- }
- }
- }
- }
-
- return 0;
-}
-#endif
-
-#ifdef USE_EARLYSUSPEND
-static void synaptics_rmi4_early_suspend(struct early_suspend *h)
-{
- struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- struct synaptics_rmi4_data *rmi4_data =
- container_of(h, struct synaptics_rmi4_data,
- early_suspend);
-
- if (rmi4_data->stay_awake)
- return;
-
- /*
- * During early suspend/late resume, the driver doesn't access xPU/SMMU
- * protected HW resources. So, there is no compelling need to block,
- * but notifying the userspace that a power event has occurred is
- * enough. Hence 'blocking' variable can be set to false.
- */
- synaptics_secure_touch_stop(rmi4_data, false);
-
- if (rmi4_data->enable_wakeup_gesture) {
- synaptics_rmi4_wakeup_gesture(rmi4_data, true);
- enable_irq_wake(rmi4_data->irq);
- goto exit;
- }
-
- synaptics_rmi4_irq_enable(rmi4_data, false, false);
- synaptics_rmi4_sleep_enable(rmi4_data, true);
- synaptics_rmi4_free_fingers(rmi4_data);
-
-exit:
- mutex_lock(&exp_data.mutex);
- if (!list_empty(&exp_data.list)) {
- list_for_each_entry(exp_fhandler, &exp_data.list, link)
- if (exp_fhandler->exp_fn->early_suspend != NULL)
- exp_fhandler->exp_fn->early_suspend(rmi4_data);
- }
- mutex_unlock(&exp_data.mutex);
-
- rmi4_data->suspend = true;
-
- return;
-}
-
-static void synaptics_rmi4_late_resume(struct early_suspend *h)
-{
-#ifdef FB_READY_RESET
- int retval;
-#endif
- struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- struct synaptics_rmi4_data *rmi4_data =
- container_of(h, struct synaptics_rmi4_data,
- early_suspend);
-
- if (rmi4_data->stay_awake)
- return;
-
- synaptics_secure_touch_stop(rmi4_data, false);
-
- if (rmi4_data->enable_wakeup_gesture) {
- synaptics_rmi4_wakeup_gesture(rmi4_data, false);
- disable_irq_wake(rmi4_data->irq);
- goto exit;
- }
-
- rmi4_data->current_page = MASK_8BIT;
-
- if (rmi4_data->suspend) {
- synaptics_rmi4_sleep_enable(rmi4_data, false);
- synaptics_rmi4_irq_enable(rmi4_data, true, false);
- }
-
-exit:
-#ifdef FB_READY_RESET
- if (rmi4_data->suspend) {
- retval = synaptics_rmi4_reset_device(rmi4_data, false);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to issue reset command\n",
- __func__);
- }
- }
-#endif
- mutex_lock(&exp_data.mutex);
- if (!list_empty(&exp_data.list)) {
- list_for_each_entry(exp_fhandler, &exp_data.list, link)
- if (exp_fhandler->exp_fn->late_resume != NULL)
- exp_fhandler->exp_fn->late_resume(rmi4_data);
- }
- mutex_unlock(&exp_data.mutex);
-
- rmi4_data->suspend = false;
-
- return;
-}
-#endif
-
-static int synaptics_rmi4_suspend(struct device *dev)
-{
- struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- int retval;
-
- if (rmi4_data->stay_awake)
- return 0;
-
- synaptics_secure_touch_stop(rmi4_data, true);
-
- if (rmi4_data->enable_wakeup_gesture) {
- synaptics_rmi4_wakeup_gesture(rmi4_data, true);
- enable_irq_wake(rmi4_data->irq);
- goto exit;
- }
-
- if (!rmi4_data->suspend) {
- synaptics_rmi4_irq_enable(rmi4_data, false, false);
- synaptics_rmi4_sleep_enable(rmi4_data, true);
- synaptics_rmi4_free_fingers(rmi4_data);
- }
-
- if (rmi4_data->ts_pinctrl) {
- retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
- rmi4_data->pinctrl_state_suspend);
- if (retval < 0)
- dev_err(dev, "Cannot get idle pinctrl state\n");
- goto err_pinctrl;
- }
-exit:
- mutex_lock(&exp_data.mutex);
- if (!list_empty(&exp_data.list)) {
- list_for_each_entry(exp_fhandler, &exp_data.list, link)
- if (exp_fhandler->exp_fn->suspend != NULL)
- exp_fhandler->exp_fn->suspend(rmi4_data);
- }
- mutex_unlock(&exp_data.mutex);
-
- if (!rmi4_data->suspend) {
- synaptics_rmi4_enable_reg(rmi4_data, false);
- synaptics_rmi4_get_reg(rmi4_data, false);
- }
- rmi4_data->suspend = true;
-
- return 0;
-
-err_pinctrl:
- synaptics_rmi4_sleep_enable(rmi4_data, false);
- synaptics_rmi4_irq_enable(rmi4_data, true, false);
- return retval;
-
-}
-
-static int synaptics_rmi4_resume(struct device *dev)
-{
-#ifdef FB_READY_RESET
- int retval;
-#endif
- struct synaptics_rmi4_exp_fhandler *exp_fhandler;
- struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
-
- if (rmi4_data->stay_awake)
- return 0;
-
- synaptics_secure_touch_stop(rmi4_data, true);
-
- if (rmi4_data->enable_wakeup_gesture) {
- synaptics_rmi4_wakeup_gesture(rmi4_data, false);
- disable_irq_wake(rmi4_data->irq);
- goto exit;
- }
-
- rmi4_data->current_page = MASK_8BIT;
-
- if (rmi4_data->suspend) {
- synaptics_rmi4_get_reg(rmi4_data, true);
- synaptics_rmi4_enable_reg(rmi4_data, true);
- }
-
- synaptics_rmi4_sleep_enable(rmi4_data, false);
- synaptics_rmi4_irq_enable(rmi4_data, true, false);
- if (rmi4_data->ts_pinctrl) {
- retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
- rmi4_data->pinctrl_state_active);
- if (retval < 0)
- dev_err(dev, "Cannot get default pinctrl state\n");
- }
-
-exit:
-#ifdef FB_READY_RESET
- retval = synaptics_rmi4_reset_device(rmi4_data, false);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to issue reset command\n",
- __func__);
- }
-#endif
- mutex_lock(&exp_data.mutex);
- if (!list_empty(&exp_data.list)) {
- list_for_each_entry(exp_fhandler, &exp_data.list, link)
- if (exp_fhandler->exp_fn->resume != NULL)
- exp_fhandler->exp_fn->resume(rmi4_data);
- }
- mutex_unlock(&exp_data.mutex);
-
- rmi4_data->suspend = false;
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
-#ifndef CONFIG_FB
- .suspend = synaptics_rmi4_suspend,
- .resume = synaptics_rmi4_resume,
-#endif
-};
-#endif
-
-static struct platform_driver synaptics_rmi4_driver = {
- .driver = {
- .name = PLATFORM_DRIVER_NAME,
- .owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &synaptics_rmi4_dev_pm_ops,
-#endif
- },
- .probe = synaptics_rmi4_probe,
- .remove = synaptics_rmi4_remove,
-};
-
-static int __init synaptics_rmi4_init(void)
-{
- int retval;
-
- retval = synaptics_rmi4_bus_init_v26();
- if (retval)
- return retval;
-
- return platform_driver_register(&synaptics_rmi4_driver);
-}
-
-static void __exit synaptics_rmi4_exit(void)
-{
- platform_driver_unregister(&synaptics_rmi4_driver);
-
- synaptics_rmi4_bus_exit_v26();
-
- return;
-}
-
-module_init(synaptics_rmi4_init);
-module_exit(synaptics_rmi4_exit);
-
-MODULE_AUTHOR("Synaptics, Inc.");
-MODULE_DESCRIPTION("Synaptics DSX Touch Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h
deleted file mode 100644
index 7d92791afb25..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- * 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 as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
-
-#ifndef _SYNAPTICS_DSX_RMI4_H_
-#define _SYNAPTICS_DSX_RMI4_H_
-
-#define SYNAPTICS_DS4 (1 << 0)
-#define SYNAPTICS_DS5 (1 << 1)
-#define SYNAPTICS_DSX_DRIVER_PRODUCT (SYNAPTICS_DS4 | SYNAPTICS_DS5)
-#define SYNAPTICS_DSX_DRIVER_VERSION 0x2061
-
-#include <linux/version.h>
-#ifdef CONFIG_FB
-#include <linux/notifier.h>
-#include <linux/fb.h>
-#endif
-#ifdef CONFIG_HAS_EARLYSUSPEND
-#include <linux/earlysuspend.h>
-#endif
-
-#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
-#include <linux/completion.h>
-#include <linux/atomic.h>
-#include <linux/pm_runtime.h>
-#include <linux/clk.h>
-#endif
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
-#define KERNEL_ABOVE_2_6_38
-#endif
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
-#define KERNEL_ABOVE_3_6
-#endif
-
-#ifdef KERNEL_ABOVE_2_6_38
-#define sstrtoul(...) kstrtoul(__VA_ARGS__)
-#else
-#define sstrtoul(...) strict_strtoul(__VA_ARGS__)
-#endif
-
-#define PDT_PROPS (0X00EF)
-#define PDT_START (0x00E9)
-#define PDT_END (0x00D0)
-#define PDT_ENTRY_SIZE (0x0006)
-#define PAGES_TO_SERVICE (10)
-#define PAGE_SELECT_LEN (2)
-#define ADDRESS_WORD_LEN (2)
-
-#define SYNAPTICS_RMI4_F01 (0x01)
-#define SYNAPTICS_RMI4_F11 (0x11)
-#define SYNAPTICS_RMI4_F12 (0x12)
-#define SYNAPTICS_RMI4_F1A (0x1A)
-#define SYNAPTICS_RMI4_F34 (0x34)
-#define SYNAPTICS_RMI4_F35 (0x35)
-#define SYNAPTICS_RMI4_F38 (0x38)
-#define SYNAPTICS_RMI4_F51 (0x51)
-#define SYNAPTICS_RMI4_F54 (0x54)
-#define SYNAPTICS_RMI4_F55 (0x55)
-#define SYNAPTICS_RMI4_FDB (0xDB)
-
-#define PRODUCT_INFO_SIZE 2
-#define PRODUCT_ID_SIZE 10
-#define BUILD_ID_SIZE 3
-
-#define F12_FINGERS_TO_SUPPORT 10
-#define F12_NO_OBJECT_STATUS 0x00
-#define F12_FINGER_STATUS 0x01
-#define F12_ACTIVE_STYLUS_STATUS 0x02
-#define F12_PALM_STATUS 0x03
-#define F12_HOVERING_FINGER_STATUS 0x05
-#define F12_GLOVED_FINGER_STATUS 0x06
-#define F12_NARROW_OBJECT_STATUS 0x07
-#define F12_HAND_EDGE_STATUS 0x08
-#define F12_COVER_STATUS 0x0A
-#define F12_STYLUS_STATUS 0x0B
-#define F12_ERASER_STATUS 0x0C
-#define F12_SMALL_OBJECT_STATUS 0x0D
-
-#define F12_GESTURE_DETECTION_LEN 5
-
-#define MAX_NUMBER_OF_BUTTONS 4
-#define MAX_INTR_REGISTERS 4
-
-#define MASK_16BIT 0xFFFF
-#define MASK_8BIT 0xFF
-#define MASK_7BIT 0x7F
-#define MASK_6BIT 0x3F
-#define MASK_5BIT 0x1F
-#define MASK_4BIT 0x0F
-#define MASK_3BIT 0x07
-#define MASK_2BIT 0x03
-#define MASK_1BIT 0x01
-
-#define PINCTRL_STATE_ACTIVE "pmx_ts_active"
-#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend"
-#define PINCTRL_STATE_RELEASE "pmx_ts_release"
-enum exp_fn {
- RMI_DEV = 0,
- RMI_FW_UPDATER,
- RMI_TEST_REPORTING,
- RMI_PROXIMITY,
- RMI_ACTIVE_PEN,
- RMI_GESTURE,
- RMI_VIDEO,
- RMI_DEBUG,
- RMI_LAST,
-};
-
-/*
- * struct synaptics_rmi4_fn_desc - function descriptor fields in PDT entry
- * @query_base_addr: base address for query registers
- * @cmd_base_addr: base address for command registers
- * @ctrl_base_addr: base address for control registers
- * @data_base_addr: base address for data registers
- * @intr_src_count: number of interrupt sources
- * @fn_version: version of function
- * @fn_number: function number
- */
-struct synaptics_rmi4_fn_desc {
- union {
- struct {
- unsigned char query_base_addr;
- unsigned char cmd_base_addr;
- unsigned char ctrl_base_addr;
- unsigned char data_base_addr;
- unsigned char intr_src_count:3;
- unsigned char reserved_1:2;
- unsigned char fn_version:2;
- unsigned char reserved_2:1;
- unsigned char fn_number;
- } __packed;
- unsigned char data[6];
- };
-};
-
-/*
- * synaptics_rmi4_fn_full_addr - full 16-bit base addresses
- * @query_base: 16-bit base address for query registers
- * @cmd_base: 16-bit base address for command registers
- * @ctrl_base: 16-bit base address for control registers
- * @data_base: 16-bit base address for data registers
- */
-struct synaptics_rmi4_fn_full_addr {
- unsigned short query_base;
- unsigned short cmd_base;
- unsigned short ctrl_base;
- unsigned short data_base;
-};
-
-/*
- * struct synaptics_rmi4_f11_extra_data - extra data of F$11
- * @data38_offset: offset to F11_2D_DATA38 register
- */
-struct synaptics_rmi4_f11_extra_data {
- unsigned char data38_offset;
-};
-
-/*
- * struct synaptics_rmi4_f12_extra_data - extra data of F$12
- * @data1_offset: offset to F12_2D_DATA01 register
- * @data4_offset: offset to F12_2D_DATA04 register
- * @data15_offset: offset to F12_2D_DATA15 register
- * @data15_size: size of F12_2D_DATA15 register
- * @data15_data: buffer for reading F12_2D_DATA15 register
- * @data23_offset: offset to F12_2D_DATA23 register
- * @data23_size: size of F12_2D_DATA23 register
- * @data23_data: buffer for reading F12_2D_DATA23 register
- * @ctrl20_offset: offset to F12_2D_CTRL20 register
- */
-struct synaptics_rmi4_f12_extra_data {
- unsigned char data1_offset;
- unsigned char data4_offset;
- unsigned char data15_offset;
- unsigned char data15_size;
- unsigned char data15_data[(F12_FINGERS_TO_SUPPORT + 7) / 8];
- unsigned char data23_offset;
- unsigned char data23_size;
- unsigned char data23_data[F12_FINGERS_TO_SUPPORT];
- unsigned char ctrl20_offset;
-};
-
-/*
- * struct synaptics_rmi4_fn - RMI function handler
- * @fn_number: function number
- * @num_of_data_sources: number of data sources
- * @num_of_data_points: maximum number of fingers supported
- * @intr_reg_num: index to associated interrupt register
- * @intr_mask: interrupt mask
- * @full_addr: full 16-bit base addresses of function registers
- * @link: linked list for function handlers
- * @data_size: size of private data
- * @data: pointer to private data
- * @extra: pointer to extra data
- */
-struct synaptics_rmi4_fn {
- unsigned char fn_number;
- unsigned char num_of_data_sources;
- unsigned char num_of_data_points;
- unsigned char intr_reg_num;
- unsigned char intr_mask;
- struct synaptics_rmi4_fn_full_addr full_addr;
- struct list_head link;
- int data_size;
- void *data;
- void *extra;
-};
-
-/*
- * struct synaptics_rmi4_device_info - device information
- * @version_major: RMI protocol major version number
- * @version_minor: RMI protocol minor version number
- * @manufacturer_id: manufacturer ID
- * @product_props: product properties
- * @product_info: product information
- * @product_id_string: product ID
- * @build_id: firmware build ID
- * @support_fn_list: linked list for function handlers
- */
-struct synaptics_rmi4_device_info {
- unsigned int version_major;
- unsigned int version_minor;
- unsigned char manufacturer_id;
- unsigned char product_props;
- unsigned char product_info[PRODUCT_INFO_SIZE];
- unsigned char product_id_string[PRODUCT_ID_SIZE + 1];
- unsigned char build_id[BUILD_ID_SIZE];
- struct list_head support_fn_list;
-};
-
-/*
- * struct synaptics_rmi4_data - RMI4 device instance data
- * @pdev: pointer to platform device
- * @input_dev: pointer to associated input device
- * @stylus_dev: pointer to associated stylus device
- * @hw_if: pointer to hardware interface data
- * @rmi4_mod_info: device information
- * @board_prop_dir: /sys/board_properties directory for virtual key map file
- * @pwr_reg: pointer to regulator for power control
- * @bus_reg: pointer to regulator for bus pullup control
- * @rmi4_reset_mutex: mutex for software reset
- * @rmi4_report_mutex: mutex for input event reporting
- * @rmi4_io_ctrl_mutex: mutex for communication interface I/O
- * @rmi4_exp_init_mutex: mutex for expansion function module initialization
- * @rb_work: work for rebuilding input device
- * @rb_workqueue: workqueue for rebuilding input device
- * @fb_notifier: framebuffer notifier client
- * @reset_work: work for issuing reset after display framebuffer ready
- * @reset_workqueue: workqueue for issuing reset after display framebuffer ready
- * @early_suspend: early suspend power management
- * @current_page: current RMI page for register access
- * @button_0d_enabled: switch for enabling 0d button support
- * @num_of_tx: number of Tx channels for 2D touch
- * @num_of_rx: number of Rx channels for 2D touch
- * @num_of_fingers: maximum number of fingers for 2D touch
- * @max_touch_width: maximum touch width
- * @report_enable: input data to report for F$12
- * @no_sleep_setting: default setting of NoSleep in F01_RMI_CTRL00 register
- * @gesture_detection: detected gesture type and properties
- * @intr_mask: interrupt enable mask
- * @button_txrx_mapping: Tx Rx mapping of 0D buttons
- * @num_of_intr_regs: number of interrupt registers
- * @f01_query_base_addr: query base address for f$01
- * @f01_cmd_base_addr: command base address for f$01
- * @f01_ctrl_base_addr: control base address for f$01
- * @f01_data_base_addr: data base address for f$01
- * @firmware_id: firmware build ID
- * @irq: attention interrupt
- * @sensor_max_x: maximum x coordinate for 2D touch
- * @sensor_max_y: maximum y coordinate for 2D touch
- * @flash_prog_mode: flag to indicate flash programming mode status
- * @irq_enabled: flag to indicate attention interrupt enable status
- * @fingers_on_2d: flag to indicate presence of fingers in 2D area
- * @suspend: flag to indicate whether in suspend state
- * @sensor_sleep: flag to indicate sleep state of sensor
- * @stay_awake: flag to indicate whether to stay awake during suspend
- * @fb_ready: flag to indicate whether display framebuffer in ready state
- * @f11_wakeup_gesture: flag to indicate support for wakeup gestures in F$11
- * @f12_wakeup_gesture: flag to indicate support for wakeup gestures in F$12
- * @enable_wakeup_gesture: flag to indicate usage of wakeup gestures
- * @wedge_sensor: flag to indicate use of wedge sensor
- * @report_pressure: flag to indicate reporting of pressure data
- * @stylus_enable: flag to indicate reporting of stylus data
- * @eraser_enable: flag to indicate reporting of eraser data
- * @external_afe_buttons: flag to indicate presence of external AFE buttons
- * @reset_device: pointer to device reset function
- * @irq_enable: pointer to interrupt enable function
- * @sleep_enable: pointer to sleep enable function
- * @report_touch: pointer to touch reporting function
- */
-struct synaptics_rmi4_data {
- struct platform_device *pdev;
- struct input_dev *input_dev;
- struct input_dev *stylus_dev;
- const struct synaptics_dsx_hw_interface *hw_if;
- struct synaptics_rmi4_device_info rmi4_mod_info;
- struct kobject *board_prop_dir;
- struct regulator *pwr_reg;
- struct regulator *bus_reg;
- struct mutex rmi4_reset_mutex;
- struct mutex rmi4_report_mutex;
- struct mutex rmi4_io_ctrl_mutex;
- struct mutex rmi4_exp_init_mutex;
- struct delayed_work rb_work;
- struct workqueue_struct *rb_workqueue;
-#ifdef CONFIG_FB
- struct work_struct fb_notify_work;
- struct notifier_block fb_notifier;
- struct work_struct reset_work;
- struct workqueue_struct *reset_workqueue;
-#endif
-#ifdef CONFIG_HAS_EARLYSUSPEND
- struct early_suspend early_suspend;
-#endif
- unsigned char current_page;
- unsigned char button_0d_enabled;
- unsigned char num_of_tx;
- unsigned char num_of_rx;
- unsigned char num_of_fingers;
- unsigned char max_touch_width;
- unsigned char report_enable;
- unsigned char no_sleep_setting;
- unsigned char gesture_detection[F12_GESTURE_DETECTION_LEN];
- unsigned char intr_mask[MAX_INTR_REGISTERS];
- unsigned char *button_txrx_mapping;
- unsigned short num_of_intr_regs;
- unsigned short f01_query_base_addr;
- unsigned short f01_cmd_base_addr;
- unsigned short f01_ctrl_base_addr;
- unsigned short f01_data_base_addr;
- unsigned int firmware_id;
- int irq;
- int sensor_max_x;
- int sensor_max_y;
- bool flash_prog_mode;
- bool irq_enabled;
- bool fingers_on_2d;
- bool suspend;
- bool sensor_sleep;
- bool stay_awake;
- bool fb_ready;
- bool f11_wakeup_gesture;
- bool f12_wakeup_gesture;
- bool enable_wakeup_gesture;
- bool wedge_sensor;
- bool report_pressure;
- bool stylus_enable;
- bool eraser_enable;
- bool external_afe_buttons;
- int (*reset_device)(struct synaptics_rmi4_data *rmi4_data,
- bool rebuild);
- int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable,
- bool attn_only);
- void (*sleep_enable)(struct synaptics_rmi4_data *rmi4_data,
- bool enable);
- void (*report_touch)(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn *fhandler);
- struct pinctrl *ts_pinctrl;
- struct pinctrl_state *pinctrl_state_active;
- struct pinctrl_state *pinctrl_state_suspend;
- struct pinctrl_state *pinctrl_state_release;
-#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
- atomic_t st_enabled;
- atomic_t st_pending_irqs;
- struct completion st_powerdown;
- struct completion st_irq_processed;
- bool st_initialized;
- struct clk *core_clk;
- struct clk *iface_clk;
-#endif
-};
-
-struct synaptics_dsx_bus_access {
- unsigned char type;
- int (*read)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
- unsigned char *data, unsigned short length);
- int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
- unsigned char *data, unsigned short length);
-#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
- int (*get)(struct synaptics_rmi4_data *rmi4_data);
- void (*put)(struct synaptics_rmi4_data *rmi4_data);
-#endif
-};
-
-struct synaptics_dsx_hw_interface {
- struct synaptics_dsx_board_data *board_data;
- const struct synaptics_dsx_bus_access *bus_access;
- int (*bl_hw_init)(struct synaptics_rmi4_data *rmi4_data);
- int (*ui_hw_init)(struct synaptics_rmi4_data *rmi4_data);
-};
-
-struct synaptics_rmi4_exp_fn {
- enum exp_fn fn_type;
- int (*init)(struct synaptics_rmi4_data *rmi4_data);
- void (*remove)(struct synaptics_rmi4_data *rmi4_data);
- void (*reset)(struct synaptics_rmi4_data *rmi4_data);
- void (*reinit)(struct synaptics_rmi4_data *rmi4_data);
- void (*early_suspend)(struct synaptics_rmi4_data *rmi4_data);
- void (*suspend)(struct synaptics_rmi4_data *rmi4_data);
- void (*resume)(struct synaptics_rmi4_data *rmi4_data);
- void (*late_resume)(struct synaptics_rmi4_data *rmi4_data);
- void (*attn)(struct synaptics_rmi4_data *rmi4_data,
- unsigned char intr_mask);
-};
-
-int synaptics_rmi4_bus_init_v26(void);
-
-void synaptics_rmi4_bus_exit_v26(void);
-
-void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn_module,
- bool insert);
-
-int synaptics_fw_updater(const unsigned char *fw_data);
-
-static inline int synaptics_rmi4_reg_read(
- struct synaptics_rmi4_data *rmi4_data,
- unsigned short addr,
- unsigned char *data,
- unsigned short len)
-{
- return rmi4_data->hw_if->bus_access->read(rmi4_data, addr, data, len);
-}
-
-static inline int synaptics_rmi4_reg_write(
- struct synaptics_rmi4_data *rmi4_data,
- unsigned short addr,
- unsigned char *data,
- unsigned short len)
-{
- return rmi4_data->hw_if->bus_access->write(rmi4_data, addr, data, len);
-}
-
-#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
-static inline int synaptics_rmi4_bus_get(struct synaptics_rmi4_data *rmi4_data)
-{
- return rmi4_data->hw_if->bus_access->get(rmi4_data);
-}
-static inline void synaptics_rmi4_bus_put(struct synaptics_rmi4_data *rmi4_data)
-{
- rmi4_data->hw_if->bus_access->put(rmi4_data);
-}
-#endif
-
-static inline int secure_memcpy(unsigned char *dest, unsigned int dest_size,
- const unsigned char *src, unsigned int src_size,
- unsigned int count)
-{
- if (dest == NULL || src == NULL)
- return -EINVAL;
-
- if (count > dest_size || count > src_size)
- return -EINVAL;
-
- memcpy((void *)dest, (const void *)src, count);
-
- return 0;
-}
-
-static inline void batohs(unsigned short *dest, unsigned char *src)
-{
- *dest = src[1] * 0x100 + src[0];
-}
-
-static inline void hstoba(unsigned char *dest, unsigned short src)
-{
- dest[0] = src % 0x100;
- dest[1] = src / 0x100;
-}
-
-#endif
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
deleted file mode 100644
index 168318f85e53..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_fw_update.c
+++ /dev/null
@@ -1,4440 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/firmware.h>
-#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx_v2_6.h>
-#include "synaptics_dsx_core.h"
-
-#define FW_IMAGE_NAME "synaptics/startup_fw_update.img"
-/*
-#define DO_STARTUP_FW_UPDATE
-*/
-/*
-#ifdef DO_STARTUP_FW_UPDATE
-#ifdef CONFIG_FB
-#define WAIT_FOR_FB_READY
-#define FB_READY_WAIT_MS 100
-#define FB_READY_TIMEOUT_S 30
-#endif
-#endif
-*/
-#define FORCE_UPDATE false
-#define DO_LOCKDOWN false
-
-#define MAX_IMAGE_NAME_LEN 256
-#define MAX_FIRMWARE_ID_LEN 10
-
-#define IMAGE_HEADER_VERSION_05 0x05
-#define IMAGE_HEADER_VERSION_06 0x06
-#define IMAGE_HEADER_VERSION_10 0x10
-
-#define IMAGE_AREA_OFFSET 0x100
-#define LOCKDOWN_SIZE 0x50
-
-#define V5V6_BOOTLOADER_ID_OFFSET 0
-#define V5V6_CONFIG_ID_SIZE 4
-
-#define V5_PROPERTIES_OFFSET 2
-#define V5_BLOCK_SIZE_OFFSET 3
-#define V5_BLOCK_COUNT_OFFSET 5
-#define V5_BLOCK_NUMBER_OFFSET 0
-#define V5_BLOCK_DATA_OFFSET 2
-
-#define V6_PROPERTIES_OFFSET 1
-#define V6_BLOCK_SIZE_OFFSET 2
-#define V6_BLOCK_COUNT_OFFSET 3
-#define V6_PROPERTIES_2_OFFSET 4
-#define V6_GUEST_CODE_BLOCK_COUNT_OFFSET 5
-#define V6_BLOCK_NUMBER_OFFSET 0
-#define V6_BLOCK_DATA_OFFSET 1
-#define V6_FLASH_COMMAND_OFFSET 2
-#define V6_FLASH_STATUS_OFFSET 3
-
-#define V7_CONFIG_ID_SIZE 32
-
-#define V7_FLASH_STATUS_OFFSET 0
-#define V7_PARTITION_ID_OFFSET 1
-#define V7_BLOCK_NUMBER_OFFSET 2
-#define V7_TRANSFER_LENGTH_OFFSET 3
-#define V7_COMMAND_OFFSET 4
-#define V7_PAYLOAD_OFFSET 5
-
-#define V7_PARTITION_SUPPORT_BYTES 4
-
-#define F35_ERROR_CODE_OFFSET 0
-#define F35_CHUNK_NUM_LSB_OFFSET 0
-#define F35_CHUNK_NUM_MSB_OFFSET 1
-#define F35_CHUNK_DATA_OFFSET 2
-#define F35_CHUNK_COMMAND_OFFSET 18
-
-#define F35_CHUNK_SIZE 16
-#define F35_ERASE_ALL_WAIT_MS 3000
-#define F35_RESET_WAIT_MS 250
-
-#define SLEEP_MODE_NORMAL (0x00)
-#define SLEEP_MODE_SENSOR_SLEEP (0x01)
-#define SLEEP_MODE_RESERVED0 (0x02)
-#define SLEEP_MODE_RESERVED1 (0x03)
-
-#define ENABLE_WAIT_MS (1 * 1000)
-#define WRITE_WAIT_MS (3 * 1000)
-#define ERASE_WAIT_MS (5 * 1000)
-
-#define MIN_SLEEP_TIME_US 50
-#define MAX_SLEEP_TIME_US 100
-
-#define INT_DISABLE_WAIT_MS 20
-#define ENTER_FLASH_PROG_WAIT_MS 20
-
-static int fwu_do_reflash(void);
-
-static int fwu_recovery_check_status(void);
-
-static ssize_t fwu_sysfs_show_image(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
-
-static ssize_t fwu_sysfs_store_image(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
-
-static ssize_t fwu_sysfs_do_recovery_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t fwu_sysfs_write_config_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t fwu_sysfs_read_config_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t fwu_sysfs_config_area_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t fwu_sysfs_image_name_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t fwu_sysfs_image_size_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t fwu_sysfs_block_size_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t fwu_sysfs_firmware_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t fwu_sysfs_configuration_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t fwu_sysfs_perm_config_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t fwu_sysfs_guest_code_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t fwu_sysfs_write_guest_code_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-enum f34_version {
- F34_V0 = 0,
- F34_V1,
- F34_V2,
-};
-
-enum bl_version {
- BL_V5 = 5,
- BL_V6 = 6,
- BL_V7 = 7,
- BL_V8 = 8,
-};
-
-enum flash_area {
- NONE = 0,
- UI_FIRMWARE,
- UI_CONFIG,
-};
-
-enum update_mode {
- NORMAL = 1,
- FORCE = 2,
- LOCKDOWN = 8,
-};
-
-enum config_area {
- UI_CONFIG_AREA = 0,
- PM_CONFIG_AREA,
- BL_CONFIG_AREA,
- DP_CONFIG_AREA,
- FLASH_CONFIG_AREA,
-};
-
-enum v7_status {
- SUCCESS = 0x00,
- DEVICE_NOT_IN_BOOTLOADER_MODE,
- INVALID_PARTITION,
- INVALID_COMMAND,
- INVALID_BLOCK_OFFSET,
- INVALID_TRANSFER,
- NOT_ERASED,
- FLASH_PROGRAMMING_KEY_INCORRECT,
- BAD_PARTITION_TABLE,
- CHECKSUM_FAILED,
- FLASH_HARDWARE_FAILURE = 0x1f,
-};
-
-enum v7_partition_id {
- BOOTLOADER_PARTITION = 0x01,
- DEVICE_CONFIG_PARTITION,
- FLASH_CONFIG_PARTITION,
- MANUFACTURING_BLOCK_PARTITION,
- GUEST_SERIALIZATION_PARTITION,
- GLOBAL_PARAMETERS_PARTITION,
- CORE_CODE_PARTITION,
- CORE_CONFIG_PARTITION,
- GUEST_CODE_PARTITION,
- DISPLAY_CONFIG_PARTITION,
-};
-
-enum v7_flash_command {
- CMD_V7_IDLE = 0x00,
- CMD_V7_ENTER_BL,
- CMD_V7_READ,
- CMD_V7_WRITE,
- CMD_V7_ERASE,
- CMD_V7_ERASE_AP,
- CMD_V7_SENSOR_ID,
-};
-
-enum v5v6_flash_command {
- CMD_V5V6_IDLE = 0x0,
- CMD_V5V6_WRITE_FW = 0x2,
- CMD_V5V6_ERASE_ALL = 0x3,
- CMD_V5V6_WRITE_LOCKDOWN = 0x4,
- CMD_V5V6_READ_CONFIG = 0x5,
- CMD_V5V6_WRITE_CONFIG = 0x6,
- CMD_V5V6_ERASE_UI_CONFIG = 0x7,
- CMD_V5V6_ERASE_BL_CONFIG = 0x9,
- CMD_V5V6_ERASE_DISP_CONFIG = 0xa,
- CMD_V5V6_ERASE_GUEST_CODE = 0xb,
- CMD_V5V6_WRITE_GUEST_CODE = 0xc,
- CMD_V5V6_ENABLE_FLASH_PROG = 0xf,
-};
-
-enum flash_command {
- CMD_IDLE = 0,
- CMD_WRITE_FW,
- CMD_WRITE_CONFIG,
- CMD_WRITE_LOCKDOWN,
- CMD_WRITE_GUEST_CODE,
- CMD_READ_CONFIG,
- CMD_ERASE_ALL,
- CMD_ERASE_UI_FIRMWARE,
- CMD_ERASE_UI_CONFIG,
- CMD_ERASE_BL_CONFIG,
- CMD_ERASE_DISP_CONFIG,
- CMD_ERASE_FLASH_CONFIG,
- CMD_ERASE_GUEST_CODE,
- CMD_ENABLE_FLASH_PROG,
-};
-
-enum f35_flash_command {
- CMD_F35_IDLE = 0x0,
- CMD_F35_RESERVED = 0x1,
- CMD_F35_WRITE_CHUNK = 0x2,
- CMD_F35_ERASE_ALL = 0x3,
- CMD_F35_RESET = 0x10,
-};
-
-enum container_id {
- TOP_LEVEL_CONTAINER = 0,
- UI_CONTAINER,
- UI_CONFIG_CONTAINER,
- BL_CONTAINER,
- BL_IMAGE_CONTAINER,
- BL_CONFIG_CONTAINER,
- BL_LOCKDOWN_INFO_CONTAINER,
- PERMANENT_CONFIG_CONTAINER,
- GUEST_CODE_CONTAINER,
- BL_PROTOCOL_DESCRIPTOR_CONTAINER,
- UI_PROTOCOL_DESCRIPTOR_CONTAINER,
- RMI_SELF_DISCOVERY_CONTAINER,
- RMI_PAGE_CONTENT_CONTAINER,
- GENERAL_INFORMATION_CONTAINER,
- DEVICE_CONFIG_CONTAINER,
- FLASH_CONFIG_CONTAINER,
- GUEST_SERIALIZATION_CONTAINER,
- GLOBAL_PARAMETERS_CONTAINER,
- CORE_CODE_CONTAINER,
- CORE_CONFIG_CONTAINER,
- DISPLAY_CONFIG_CONTAINER,
-};
-
-struct pdt_properties {
- union {
- struct {
- unsigned char reserved_1:6;
- unsigned char has_bsr:1;
- unsigned char reserved_2:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct partition_table {
- unsigned char partition_id:5;
- unsigned char byte_0_reserved:3;
- unsigned char byte_1_reserved;
- unsigned char partition_length_7_0;
- unsigned char partition_length_15_8;
- unsigned char start_physical_address_7_0;
- unsigned char start_physical_address_15_8;
- unsigned char partition_properties_7_0;
- unsigned char partition_properties_15_8;
-} __packed;
-
-struct f01_device_control {
- union {
- struct {
- unsigned char sleep_mode:2;
- unsigned char nosleep:1;
- unsigned char reserved:2;
- unsigned char charger_connected:1;
- unsigned char report_rate:1;
- unsigned char configured:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f34_v7_query_0 {
- union {
- struct {
- unsigned char subpacket_1_size:3;
- unsigned char has_config_id:1;
- unsigned char f34_query0_b4:1;
- unsigned char has_thqa:1;
- unsigned char f34_query0_b6__7:2;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f34_v7_query_1_7 {
- union {
- struct {
- /* query 1 */
- unsigned char bl_minor_revision;
- unsigned char bl_major_revision;
-
- /* query 2 */
- unsigned char bl_fw_id_7_0;
- unsigned char bl_fw_id_15_8;
- unsigned char bl_fw_id_23_16;
- unsigned char bl_fw_id_31_24;
-
- /* query 3 */
- unsigned char minimum_write_size;
- unsigned char block_size_7_0;
- unsigned char block_size_15_8;
- unsigned char flash_page_size_7_0;
- unsigned char flash_page_size_15_8;
-
- /* query 4 */
- unsigned char adjustable_partition_area_size_7_0;
- unsigned char adjustable_partition_area_size_15_8;
-
- /* query 5 */
- unsigned char flash_config_length_7_0;
- unsigned char flash_config_length_15_8;
-
- /* query 6 */
- unsigned char payload_length_7_0;
- unsigned char payload_length_15_8;
-
- /* query 7 */
- unsigned char f34_query7_b0:1;
- unsigned char has_bootloader:1;
- unsigned char has_device_config:1;
- unsigned char has_flash_config:1;
- unsigned char has_manufacturing_block:1;
- unsigned char has_guest_serialization:1;
- unsigned char has_global_parameters:1;
- unsigned char has_core_code:1;
- unsigned char has_core_config:1;
- unsigned char has_guest_code:1;
- unsigned char has_display_config:1;
- unsigned char f34_query7_b11__15:5;
- unsigned char f34_query7_b16__23;
- unsigned char f34_query7_b24__31;
- } __packed;
- unsigned char data[21];
- };
-};
-
-struct f34_v7_data0 {
- union {
- struct {
- unsigned char operation_status:5;
- unsigned char device_cfg_status:2;
- unsigned char bl_mode:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f34_v7_data_1_5 {
- union {
- struct {
- unsigned char partition_id:5;
- unsigned char f34_data1_b5__7:3;
- unsigned char block_offset_7_0;
- unsigned char block_offset_15_8;
- unsigned char transfer_length_7_0;
- unsigned char transfer_length_15_8;
- unsigned char command;
- unsigned char payload_0;
- unsigned char payload_1;
- } __packed;
- unsigned char data[8];
- };
-};
-
-struct f34_v5v6_flash_properties {
- union {
- struct {
- unsigned char reg_map:1;
- unsigned char unlocked:1;
- unsigned char has_config_id:1;
- unsigned char has_pm_config:1;
- unsigned char has_bl_config:1;
- unsigned char has_disp_config:1;
- unsigned char has_ctrl1:1;
- unsigned char has_query4:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f34_v5v6_flash_properties_2 {
- union {
- struct {
- unsigned char has_guest_code:1;
- unsigned char reserved:7;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct register_offset {
- unsigned char properties;
- unsigned char properties_2;
- unsigned char block_size;
- unsigned char block_count;
- unsigned char gc_block_count;
- unsigned char flash_status;
- unsigned char partition_id;
- unsigned char block_number;
- unsigned char transfer_length;
- unsigned char flash_cmd;
- unsigned char payload;
-};
-
-struct block_count {
- unsigned short ui_firmware;
- unsigned short ui_config;
- unsigned short dp_config;
- unsigned short pm_config;
- unsigned short fl_config;
- unsigned short bl_image;
- unsigned short bl_config;
- unsigned short lockdown;
- unsigned short guest_code;
- unsigned short total_count;
-};
-
-struct physical_address {
- unsigned short ui_firmware;
- unsigned short ui_config;
- unsigned short dp_config;
- unsigned short fl_config;
- unsigned short guest_code;
-};
-
-struct container_descriptor {
- unsigned char content_checksum[4];
- unsigned char container_id[2];
- unsigned char minor_version;
- unsigned char major_version;
- unsigned char reserved_08;
- unsigned char reserved_09;
- unsigned char reserved_0a;
- unsigned char reserved_0b;
- unsigned char container_option_flags[4];
- unsigned char content_options_length[4];
- unsigned char content_options_address[4];
- unsigned char content_length[4];
- unsigned char content_address[4];
-};
-
-struct image_header_10 {
- unsigned char checksum[4];
- unsigned char reserved_04;
- unsigned char reserved_05;
- unsigned char minor_header_version;
- unsigned char major_header_version;
- unsigned char reserved_08;
- unsigned char reserved_09;
- unsigned char reserved_0a;
- unsigned char reserved_0b;
- unsigned char top_level_container_start_addr[4];
-};
-
-struct image_header_05_06 {
- /* 0x00 - 0x0f */
- unsigned char checksum[4];
- unsigned char reserved_04;
- unsigned char reserved_05;
- unsigned char options_firmware_id:1;
- unsigned char options_bootloader:1;
- unsigned char options_guest_code:1;
- unsigned char options_tddi:1;
- unsigned char options_reserved:4;
- unsigned char header_version;
- unsigned char firmware_size[4];
- unsigned char config_size[4];
- /* 0x10 - 0x1f */
- unsigned char product_id[PRODUCT_ID_SIZE];
- unsigned char package_id[2];
- unsigned char package_id_revision[2];
- unsigned char product_info[PRODUCT_INFO_SIZE];
- /* 0x20 - 0x2f */
- unsigned char bootloader_addr[4];
- unsigned char bootloader_size[4];
- unsigned char ui_addr[4];
- unsigned char ui_size[4];
- /* 0x30 - 0x3f */
- unsigned char ds_id[16];
- /* 0x40 - 0x4f */
- union {
- struct {
- unsigned char cstmr_product_id[PRODUCT_ID_SIZE];
- unsigned char reserved_4a_4f[6];
- };
- struct {
- unsigned char dsp_cfg_addr[4];
- unsigned char dsp_cfg_size[4];
- unsigned char reserved_48_4f[8];
- };
- };
- /* 0x50 - 0x53 */
- unsigned char firmware_id[4];
-};
-
-struct block_data {
- unsigned int size;
- const unsigned char *data;
-};
-
-struct image_metadata {
- bool contains_firmware_id;
- bool contains_bootloader;
- bool contains_guest_code;
- bool contains_disp_config;
- bool contains_perm_config;
- bool contains_flash_config;
- unsigned int firmware_id;
- unsigned int checksum;
- unsigned int bootloader_size;
- unsigned int disp_config_offset;
- unsigned char bl_version;
- unsigned char product_id[PRODUCT_ID_SIZE + 1];
- unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1];
- struct block_data bootloader;
- struct block_data ui_firmware;
- struct block_data ui_config;
- struct block_data dp_config;
- struct block_data pm_config;
- struct block_data fl_config;
- struct block_data bl_image;
- struct block_data bl_config;
- struct block_data lockdown;
- struct block_data guest_code;
- struct block_count blkcount;
- struct physical_address phyaddr;
-};
-
-struct synaptics_rmi4_fwu_handle {
- enum bl_version bl_version;
- bool initialized;
- bool in_bl_mode;
- bool in_ub_mode;
- bool force_update;
- bool do_lockdown;
- bool has_guest_code;
- bool new_partition_table;
- unsigned int data_pos;
- unsigned char *ext_data_source;
- unsigned char *read_config_buf;
- unsigned char intr_mask;
- unsigned char command;
- unsigned char bootloader_id[2];
- unsigned char config_id[32];
- unsigned char flash_status;
- unsigned char partitions;
- unsigned short block_size;
- unsigned short config_size;
- unsigned short config_area;
- unsigned short config_block_count;
- unsigned short flash_config_length;
- unsigned short payload_length;
- unsigned short partition_table_bytes;
- unsigned short read_config_buf_size;
- const unsigned char *config_data;
- const unsigned char *image;
- unsigned char *image_name;
- unsigned int image_size;
- struct image_metadata img;
- struct register_offset off;
- struct block_count blkcount;
- struct physical_address phyaddr;
- struct f34_v5v6_flash_properties flash_properties;
- struct synaptics_rmi4_fn_desc f34_fd;
- struct synaptics_rmi4_fn_desc f35_fd;
- struct synaptics_rmi4_data *rmi4_data;
- struct workqueue_struct *fwu_workqueue;
- struct work_struct fwu_work;
-};
-
-static struct bin_attribute dev_attr_data = {
- .attr = {
- .name = "data",
- .mode = (S_IRUGO | S_IWUGO),
- },
- .size = 0,
- .read = fwu_sysfs_show_image,
- .write = fwu_sysfs_store_image,
-};
-
-static struct device_attribute attrs[] = {
- __ATTR(dorecovery, S_IWUSR | S_IWGRP,
- NULL,
- fwu_sysfs_do_recovery_store),
- __ATTR(doreflash, S_IWUSR | S_IWGRP,
- NULL,
- fwu_sysfs_do_reflash_store),
- __ATTR(writeconfig, S_IWUSR | S_IWGRP,
- NULL,
- fwu_sysfs_write_config_store),
- __ATTR(readconfig, S_IWUSR | S_IWGRP,
- NULL,
- fwu_sysfs_read_config_store),
- __ATTR(configarea, S_IWUSR | S_IWGRP,
- NULL,
- fwu_sysfs_config_area_store),
- __ATTR(imagename, S_IWUSR | S_IWGRP,
- NULL,
- fwu_sysfs_image_name_store),
- __ATTR(imagesize, S_IWUSR | S_IWGRP,
- NULL,
- fwu_sysfs_image_size_store),
- __ATTR(blocksize, S_IRUGO,
- fwu_sysfs_block_size_show,
- NULL),
- __ATTR(fwblockcount, S_IRUGO,
- fwu_sysfs_firmware_block_count_show,
- NULL),
- __ATTR(configblockcount, S_IRUGO,
- fwu_sysfs_configuration_block_count_show,
- NULL),
- __ATTR(dispconfigblockcount, S_IRUGO,
- fwu_sysfs_disp_config_block_count_show,
- NULL),
- __ATTR(permconfigblockcount, S_IRUGO,
- fwu_sysfs_perm_config_block_count_show,
- NULL),
- __ATTR(blconfigblockcount, S_IRUGO,
- fwu_sysfs_bl_config_block_count_show,
- NULL),
- __ATTR(guestcodeblockcount, S_IRUGO,
- fwu_sysfs_guest_code_block_count_show,
- NULL),
- __ATTR(writeguestcode, S_IWUSR | S_IWGRP,
- NULL,
- fwu_sysfs_write_guest_code_store),
-};
-
-static struct synaptics_rmi4_fwu_handle *fwu;
-
-DECLARE_COMPLETION(fwu_remove_complete);
-
-static unsigned int le_to_uint(const unsigned char *ptr)
-{
- return (unsigned int)ptr[0] +
- (unsigned int)ptr[1] * 0x100 +
- (unsigned int)ptr[2] * 0x10000 +
- (unsigned int)ptr[3] * 0x1000000;
-}
-
-static int fwu_allocate_read_config_buf(unsigned int count)
-{
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- if (count > fwu->read_config_buf_size) {
- kfree(fwu->read_config_buf);
- fwu->read_config_buf = kzalloc(count, GFP_KERNEL);
- if (!fwu->read_config_buf) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for fwu->read_config_buf\n",
- __func__);
- fwu->read_config_buf_size = 0;
- return -ENOMEM;
- }
- fwu->read_config_buf_size = count;
- }
-
- return 0;
-}
-
-static void fwu_compare_partition_tables(void)
-{
- if (fwu->phyaddr.ui_firmware != fwu->img.phyaddr.ui_firmware) {
- fwu->new_partition_table = true;
- return;
- }
-
- if (fwu->phyaddr.ui_config != fwu->img.phyaddr.ui_config) {
- fwu->new_partition_table = true;
- return;
- }
-
- if (fwu->flash_properties.has_disp_config) {
- if (fwu->phyaddr.dp_config != fwu->img.phyaddr.dp_config) {
- fwu->new_partition_table = true;
- return;
- }
- }
-
- if (fwu->has_guest_code) {
- if (fwu->phyaddr.guest_code != fwu->img.phyaddr.guest_code) {
- fwu->new_partition_table = true;
- return;
- }
- }
-
- fwu->new_partition_table = false;
-
- return;
-}
-
-static void fwu_parse_partition_table(const unsigned char *partition_table,
- struct block_count *blkcount, struct physical_address *phyaddr)
-{
- unsigned char ii;
- unsigned char index;
- unsigned char offset;
- unsigned short partition_length;
- unsigned short physical_address;
- struct partition_table *ptable;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- for (ii = 0; ii < fwu->partitions; ii++) {
- index = ii * 8 + 2;
- ptable = (struct partition_table *)&partition_table[index];
- partition_length = ptable->partition_length_15_8 << 8 |
- ptable->partition_length_7_0;
- physical_address = ptable->start_physical_address_15_8 << 8 |
- ptable->start_physical_address_7_0;
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Partition entry %d:\n",
- __func__, ii);
- for (offset = 0; offset < 8; offset++) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: 0x%02x\n",
- __func__,
- partition_table[index + offset]);
- }
- switch (ptable->partition_id) {
- case CORE_CODE_PARTITION:
- blkcount->ui_firmware = partition_length;
- phyaddr->ui_firmware = physical_address;
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Core code block count: %d\n",
- __func__, blkcount->ui_firmware);
- blkcount->total_count += partition_length;
- break;
- case CORE_CONFIG_PARTITION:
- blkcount->ui_config = partition_length;
- phyaddr->ui_config = physical_address;
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Core config block count: %d\n",
- __func__, blkcount->ui_config);
- blkcount->total_count += partition_length;
- break;
- case BOOTLOADER_PARTITION:
- blkcount->bl_image = partition_length;
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Core config block count: %d\n",
- __func__, blkcount->ui_config);
- blkcount->total_count += partition_length;
- break;
- case DISPLAY_CONFIG_PARTITION:
- blkcount->dp_config = partition_length;
- phyaddr->dp_config = physical_address;
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Display config block count: %d\n",
- __func__, blkcount->dp_config);
- blkcount->total_count += partition_length;
- break;
- case FLASH_CONFIG_PARTITION:
- blkcount->fl_config = partition_length;
- phyaddr->fl_config = physical_address;
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Flash config block count: %d\n",
- __func__, blkcount->fl_config);
- blkcount->total_count += partition_length;
- break;
- case GUEST_CODE_PARTITION:
- blkcount->guest_code = partition_length;
- phyaddr->guest_code = physical_address;
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Guest code block count: %d\n",
- __func__, blkcount->guest_code);
- blkcount->total_count += partition_length;
- break;
- case GUEST_SERIALIZATION_PARTITION:
- blkcount->pm_config = partition_length;
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Guest serialization block count: %d\n",
- __func__, blkcount->pm_config);
- blkcount->total_count += partition_length;
- break;
- case GLOBAL_PARAMETERS_PARTITION:
- blkcount->bl_config = partition_length;
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Global parameters block count: %d\n",
- __func__, blkcount->bl_config);
- blkcount->total_count += partition_length;
- break;
- case DEVICE_CONFIG_PARTITION:
- blkcount->lockdown = partition_length;
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Device config block count: %d\n",
- __func__, blkcount->lockdown);
- blkcount->total_count += partition_length;
- break;
- };
- }
-
- return;
-}
-
-static void fwu_parse_image_header_10_bl_container(const unsigned char *image)
-{
- unsigned char ii;
- unsigned char num_of_containers;
- unsigned int addr;
- unsigned int container_id;
- unsigned int length;
- const unsigned char *content;
- struct container_descriptor *descriptor;
-
- num_of_containers = (fwu->img.bootloader.size - 4) / 4;
-
- for (ii = 1; ii <= num_of_containers; ii++) {
- addr = le_to_uint(fwu->img.bootloader.data + (ii * 4));
- descriptor = (struct container_descriptor *)(image + addr);
- container_id = descriptor->container_id[0] |
- descriptor->container_id[1] << 8;
- content = image + le_to_uint(descriptor->content_address);
- length = le_to_uint(descriptor->content_length);
- switch (container_id) {
- case BL_IMAGE_CONTAINER:
- fwu->img.bl_image.data = content;
- fwu->img.bl_image.size = length;
- break;
- case BL_CONFIG_CONTAINER:
- case GLOBAL_PARAMETERS_CONTAINER:
- fwu->img.bl_config.data = content;
- fwu->img.bl_config.size = length;
- break;
- case BL_LOCKDOWN_INFO_CONTAINER:
- case DEVICE_CONFIG_CONTAINER:
- fwu->img.lockdown.data = content;
- fwu->img.lockdown.size = length;
- break;
- default:
- break;
- };
- }
-
- return;
-}
-
-static void fwu_parse_image_header_10(void)
-{
- unsigned char ii;
- unsigned char num_of_containers;
- unsigned int addr;
- unsigned int offset;
- unsigned int container_id;
- unsigned int length;
- const unsigned char *image;
- const unsigned char *content;
- struct container_descriptor *descriptor;
- struct image_header_10 *header;
-
- image = fwu->image;
- header = (struct image_header_10 *)image;
-
- fwu->img.checksum = le_to_uint(header->checksum);
-
- /* address of top level container */
- offset = le_to_uint(header->top_level_container_start_addr);
- descriptor = (struct container_descriptor *)(image + offset);
-
- /* address of top level container content */
- offset = le_to_uint(descriptor->content_address);
- num_of_containers = le_to_uint(descriptor->content_length) / 4;
-
- for (ii = 0; ii < num_of_containers; ii++) {
- addr = le_to_uint(image + offset);
- offset += 4;
- descriptor = (struct container_descriptor *)(image + addr);
- container_id = descriptor->container_id[0] |
- descriptor->container_id[1] << 8;
- content = image + le_to_uint(descriptor->content_address);
- length = le_to_uint(descriptor->content_length);
- switch (container_id) {
- case UI_CONTAINER:
- case CORE_CODE_CONTAINER:
- fwu->img.ui_firmware.data = content;
- fwu->img.ui_firmware.size = length;
- break;
- case UI_CONFIG_CONTAINER:
- case CORE_CONFIG_CONTAINER:
- fwu->img.ui_config.data = content;
- fwu->img.ui_config.size = length;
- break;
- case BL_CONTAINER:
- fwu->img.bl_version = *content;
- fwu->img.bootloader.data = content;
- fwu->img.bootloader.size = length;
- fwu_parse_image_header_10_bl_container(image);
- break;
- case GUEST_CODE_CONTAINER:
- fwu->img.contains_guest_code = true;
- fwu->img.guest_code.data = content;
- fwu->img.guest_code.size = length;
- break;
- case DISPLAY_CONFIG_CONTAINER:
- fwu->img.contains_disp_config = true;
- fwu->img.dp_config.data = content;
- fwu->img.dp_config.size = length;
- break;
- case PERMANENT_CONFIG_CONTAINER:
- case GUEST_SERIALIZATION_CONTAINER:
- fwu->img.contains_perm_config = true;
- fwu->img.pm_config.data = content;
- fwu->img.pm_config.size = length;
- break;
- case FLASH_CONFIG_CONTAINER:
- fwu->img.contains_flash_config = true;
- fwu->img.fl_config.data = content;
- fwu->img.fl_config.size = length;
- break;
- case GENERAL_INFORMATION_CONTAINER:
- fwu->img.contains_firmware_id = true;
- fwu->img.firmware_id = le_to_uint(content + 4);
- break;
- default:
- break;
- }
- }
-
- return;
-}
-
-static void fwu_parse_image_header_05_06(void)
-{
- int retval;
- const unsigned char *image;
- struct image_header_05_06 *header;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- image = fwu->image;
- header = (struct image_header_05_06 *)image;
-
- fwu->img.checksum = le_to_uint(header->checksum);
-
- fwu->img.bl_version = header->header_version;
-
- fwu->img.contains_bootloader = header->options_bootloader;
- if (fwu->img.contains_bootloader)
- fwu->img.bootloader_size = le_to_uint(header->bootloader_size);
-
- fwu->img.ui_firmware.size = le_to_uint(header->firmware_size);
- if (fwu->img.ui_firmware.size) {
- fwu->img.ui_firmware.data = image + IMAGE_AREA_OFFSET;
- if (fwu->img.contains_bootloader)
- fwu->img.ui_firmware.data += fwu->img.bootloader_size;
- }
-
- if ((fwu->img.bl_version == BL_V6) && header->options_tddi)
- fwu->img.ui_firmware.data = image + IMAGE_AREA_OFFSET;
-
- fwu->img.ui_config.size = le_to_uint(header->config_size);
- if (fwu->img.ui_config.size) {
- fwu->img.ui_config.data = fwu->img.ui_firmware.data +
- fwu->img.ui_firmware.size;
- }
-
- if ((fwu->img.bl_version == BL_V5 && fwu->img.contains_bootloader) ||
- (fwu->img.bl_version == BL_V6 && header->options_tddi))
- fwu->img.contains_disp_config = true;
- else
- fwu->img.contains_disp_config = false;
-
- if (fwu->img.contains_disp_config) {
- fwu->img.disp_config_offset = le_to_uint(header->dsp_cfg_addr);
- fwu->img.dp_config.size = le_to_uint(header->dsp_cfg_size);
- fwu->img.dp_config.data = image + fwu->img.disp_config_offset;
- } else {
- retval = secure_memcpy(fwu->img.cstmr_product_id,
- sizeof(fwu->img.cstmr_product_id),
- header->cstmr_product_id,
- sizeof(header->cstmr_product_id),
- PRODUCT_ID_SIZE);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy custom product ID string\n",
- __func__);
- }
- fwu->img.cstmr_product_id[PRODUCT_ID_SIZE] = 0;
- }
-
- fwu->img.contains_firmware_id = header->options_firmware_id;
- if (fwu->img.contains_firmware_id)
- fwu->img.firmware_id = le_to_uint(header->firmware_id);
-
- retval = secure_memcpy(fwu->img.product_id,
- sizeof(fwu->img.product_id),
- header->product_id,
- sizeof(header->product_id),
- PRODUCT_ID_SIZE);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy product ID string\n",
- __func__);
- }
- fwu->img.product_id[PRODUCT_ID_SIZE] = 0;
-
- fwu->img.lockdown.size = LOCKDOWN_SIZE;
- fwu->img.lockdown.data = image + IMAGE_AREA_OFFSET - LOCKDOWN_SIZE;
-
- return;
-}
-
-static int fwu_parse_image_info(void)
-{
- struct image_header_10 *header;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- header = (struct image_header_10 *)fwu->image;
-
- memset(&fwu->img, 0x00, sizeof(fwu->img));
-
- switch (header->major_header_version) {
- case IMAGE_HEADER_VERSION_10:
- fwu_parse_image_header_10();
- break;
- case IMAGE_HEADER_VERSION_05:
- case IMAGE_HEADER_VERSION_06:
- fwu_parse_image_header_05_06();
- break;
- default:
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Unsupported image file format (0x%02x)\n",
- __func__, header->major_header_version);
- return -EINVAL;
- }
-
- if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) {
- if (!fwu->img.contains_flash_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: No flash config found in firmware image\n",
- __func__);
- return -EINVAL;
- }
-
- fwu_parse_partition_table(fwu->img.fl_config.data,
- &fwu->img.blkcount, &fwu->img.phyaddr);
-
- fwu_compare_partition_tables();
- } else {
- fwu->new_partition_table = false;
- }
-
- return 0;
-}
-
-static int fwu_read_flash_status(void)
-{
- int retval;
- unsigned char status;
- unsigned char command;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fwu->f34_fd.data_base_addr + fwu->off.flash_status,
- &status,
- sizeof(status));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read flash status\n",
- __func__);
- return retval;
- }
-
- fwu->in_bl_mode = status >> 7;
-
- if (fwu->bl_version == BL_V5)
- fwu->flash_status = (status >> 4) & MASK_3BIT;
- else if (fwu->bl_version == BL_V6)
- fwu->flash_status = status & MASK_3BIT;
- else if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- fwu->flash_status = status & MASK_5BIT;
-
- if (fwu->flash_status != 0x00) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Flash status = %d, command = 0x%02x\n",
- __func__, fwu->flash_status, fwu->command);
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fwu->f34_fd.data_base_addr + fwu->off.flash_cmd,
- &command,
- sizeof(command));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read flash command\n",
- __func__);
- return retval;
- }
-
- if (fwu->bl_version == BL_V5)
- fwu->command = command & MASK_4BIT;
- else if (fwu->bl_version == BL_V6)
- fwu->command = command & MASK_6BIT;
- else if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- fwu->command = command;
-
- return 0;
-}
-
-static int fwu_wait_for_idle(int timeout_ms, bool poll)
-{
- int count = 0;
- int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- do {
- usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US);
-
- count++;
- if (poll || (count == timeout_count))
- fwu_read_flash_status();
-
- if ((fwu->command == CMD_IDLE) && (fwu->flash_status == 0x00))
- return 0;
- } while (count < timeout_count);
-
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Timed out waiting for idle status\n",
- __func__);
-
- return -ETIMEDOUT;
-}
-
-static int fwu_write_f34_v7_command_single_transaction(unsigned char cmd)
-{
- int retval;
- unsigned char base;
- struct f34_v7_data_1_5 data_1_5;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f34_fd.data_base_addr;
-
- memset(data_1_5.data, 0x00, sizeof(data_1_5.data));
-
- switch (cmd) {
- case CMD_ERASE_ALL:
- data_1_5.partition_id = CORE_CODE_PARTITION;
- data_1_5.command = CMD_V7_ERASE_AP;
- break;
- case CMD_ERASE_UI_FIRMWARE:
- data_1_5.partition_id = CORE_CODE_PARTITION;
- data_1_5.command = CMD_V7_ERASE;
- break;
- case CMD_ERASE_BL_CONFIG:
- data_1_5.partition_id = GLOBAL_PARAMETERS_PARTITION;
- data_1_5.command = CMD_V7_ERASE;
- break;
- case CMD_ERASE_UI_CONFIG:
- data_1_5.partition_id = CORE_CONFIG_PARTITION;
- data_1_5.command = CMD_V7_ERASE;
- break;
- case CMD_ERASE_DISP_CONFIG:
- data_1_5.partition_id = DISPLAY_CONFIG_PARTITION;
- data_1_5.command = CMD_V7_ERASE;
- break;
- case CMD_ERASE_FLASH_CONFIG:
- data_1_5.partition_id = FLASH_CONFIG_PARTITION;
- data_1_5.command = CMD_V7_ERASE;
- break;
- case CMD_ERASE_GUEST_CODE:
- data_1_5.partition_id = GUEST_CODE_PARTITION;
- data_1_5.command = CMD_V7_ERASE;
- break;
- case CMD_ENABLE_FLASH_PROG:
- data_1_5.partition_id = BOOTLOADER_PARTITION;
- data_1_5.command = CMD_V7_ENTER_BL;
- break;
- };
-
- data_1_5.payload_0 = fwu->bootloader_id[0];
- data_1_5.payload_1 = fwu->bootloader_id[1];
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.partition_id,
- data_1_5.data,
- sizeof(data_1_5.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write single transaction command\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static int fwu_write_f34_v7_command(unsigned char cmd)
-{
- int retval;
- unsigned char base;
- unsigned char command;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f34_fd.data_base_addr;
-
- switch (cmd) {
- case CMD_WRITE_FW:
- case CMD_WRITE_CONFIG:
- case CMD_WRITE_LOCKDOWN:
- case CMD_WRITE_GUEST_CODE:
- command = CMD_V7_WRITE;
- break;
- case CMD_READ_CONFIG:
- command = CMD_V7_READ;
- break;
- case CMD_ERASE_ALL:
- command = CMD_V7_ERASE_AP;
- break;
- case CMD_ERASE_UI_FIRMWARE:
- case CMD_ERASE_BL_CONFIG:
- case CMD_ERASE_UI_CONFIG:
- case CMD_ERASE_DISP_CONFIG:
- case CMD_ERASE_FLASH_CONFIG:
- case CMD_ERASE_GUEST_CODE:
- command = CMD_V7_ERASE;
- break;
- case CMD_ENABLE_FLASH_PROG:
- command = CMD_V7_ENTER_BL;
- break;
- default:
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Invalid command 0x%02x\n",
- __func__, cmd);
- return -EINVAL;
- };
-
- fwu->command = command;
-
- switch (cmd) {
- case CMD_ERASE_ALL:
- case CMD_ERASE_UI_FIRMWARE:
- case CMD_ERASE_BL_CONFIG:
- case CMD_ERASE_UI_CONFIG:
- case CMD_ERASE_DISP_CONFIG:
- case CMD_ERASE_FLASH_CONFIG:
- case CMD_ERASE_GUEST_CODE:
- case CMD_ENABLE_FLASH_PROG:
- retval = fwu_write_f34_v7_command_single_transaction(cmd);
- if (retval < 0)
- return retval;
- else
- return 0;
- default:
- break;
- };
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.flash_cmd,
- &command,
- sizeof(command));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write flash command\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static int fwu_write_f34_v5v6_command(unsigned char cmd)
-{
- int retval;
- unsigned char base;
- unsigned char command;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f34_fd.data_base_addr;
-
- switch (cmd) {
- case CMD_IDLE:
- command = CMD_V5V6_IDLE;
- break;
- case CMD_WRITE_FW:
- command = CMD_V5V6_WRITE_FW;
- break;
- case CMD_WRITE_CONFIG:
- command = CMD_V5V6_WRITE_CONFIG;
- break;
- case CMD_WRITE_LOCKDOWN:
- command = CMD_V5V6_WRITE_LOCKDOWN;
- break;
- case CMD_WRITE_GUEST_CODE:
- command = CMD_V5V6_WRITE_GUEST_CODE;
- break;
- case CMD_READ_CONFIG:
- command = CMD_V5V6_READ_CONFIG;
- break;
- case CMD_ERASE_ALL:
- command = CMD_V5V6_ERASE_ALL;
- break;
- case CMD_ERASE_UI_CONFIG:
- command = CMD_V5V6_ERASE_UI_CONFIG;
- break;
- case CMD_ERASE_DISP_CONFIG:
- command = CMD_V5V6_ERASE_DISP_CONFIG;
- break;
- case CMD_ERASE_GUEST_CODE:
- command = CMD_V5V6_ERASE_GUEST_CODE;
- break;
- case CMD_ENABLE_FLASH_PROG:
- command = CMD_V5V6_ENABLE_FLASH_PROG;
- break;
- default:
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Invalid command 0x%02x\n",
- __func__, cmd);
- return -EINVAL;
- }
-
- switch (cmd) {
- case CMD_ERASE_ALL:
- case CMD_ERASE_UI_CONFIG:
- case CMD_ERASE_DISP_CONFIG:
- case CMD_ERASE_GUEST_CODE:
- case CMD_ENABLE_FLASH_PROG:
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.payload,
- fwu->bootloader_id,
- sizeof(fwu->bootloader_id));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write bootloader ID\n",
- __func__);
- return retval;
- }
- break;
- default:
- break;
- };
-
- fwu->command = command;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.flash_cmd,
- &command,
- sizeof(command));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write command 0x%02x\n",
- __func__, command);
- return retval;
- }
-
- return 0;
-}
-
-static int fwu_write_f34_command(unsigned char cmd)
-{
- int retval;
-
- if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- retval = fwu_write_f34_v7_command(cmd);
- else
- retval = fwu_write_f34_v5v6_command(cmd);
-
- return retval;
-}
-
-static int fwu_write_f34_v7_partition_id(unsigned char cmd)
-{
- int retval;
- unsigned char base;
- unsigned char partition;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f34_fd.data_base_addr;
-
- switch (cmd) {
- case CMD_WRITE_FW:
- partition = CORE_CODE_PARTITION;
- break;
- case CMD_WRITE_CONFIG:
- case CMD_READ_CONFIG:
- if (fwu->config_area == UI_CONFIG_AREA)
- partition = CORE_CONFIG_PARTITION;
- else if (fwu->config_area == DP_CONFIG_AREA)
- partition = DISPLAY_CONFIG_PARTITION;
- else if (fwu->config_area == PM_CONFIG_AREA)
- partition = GUEST_SERIALIZATION_PARTITION;
- else if (fwu->config_area == BL_CONFIG_AREA)
- partition = GLOBAL_PARAMETERS_PARTITION;
- else if (fwu->config_area == FLASH_CONFIG_AREA)
- partition = FLASH_CONFIG_PARTITION;
- break;
- case CMD_WRITE_LOCKDOWN:
- partition = DEVICE_CONFIG_PARTITION;
- break;
- case CMD_WRITE_GUEST_CODE:
- partition = GUEST_CODE_PARTITION;
- break;
- case CMD_ERASE_ALL:
- partition = CORE_CODE_PARTITION;
- break;
- case CMD_ERASE_BL_CONFIG:
- partition = GLOBAL_PARAMETERS_PARTITION;
- break;
- case CMD_ERASE_UI_CONFIG:
- partition = CORE_CONFIG_PARTITION;
- break;
- case CMD_ERASE_DISP_CONFIG:
- partition = DISPLAY_CONFIG_PARTITION;
- break;
- case CMD_ERASE_FLASH_CONFIG:
- partition = FLASH_CONFIG_PARTITION;
- break;
- case CMD_ERASE_GUEST_CODE:
- partition = GUEST_CODE_PARTITION;
- break;
- case CMD_ENABLE_FLASH_PROG:
- partition = BOOTLOADER_PARTITION;
- break;
- default:
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Invalid command 0x%02x\n",
- __func__, cmd);
- return -EINVAL;
- };
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.partition_id,
- &partition,
- sizeof(partition));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write partition ID\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static int fwu_write_f34_partition_id(unsigned char cmd)
-{
- int retval;
-
- if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- retval = fwu_write_f34_v7_partition_id(cmd);
- else
- retval = 0;
-
- return retval;
-}
-
-static int fwu_read_f34_v7_partition_table(unsigned char *partition_table)
-{
- int retval;
- unsigned char base;
- unsigned char length[2];
- unsigned short block_number = 0;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f34_fd.data_base_addr;
-
- fwu->config_area = FLASH_CONFIG_AREA;
-
- retval = fwu_write_f34_partition_id(CMD_READ_CONFIG);
- if (retval < 0)
- return retval;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.block_number,
- (unsigned char *)&block_number,
- sizeof(block_number));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write block number\n",
- __func__);
- return retval;
- }
-
- length[0] = (unsigned char)(fwu->flash_config_length & MASK_8BIT);
- length[1] = (unsigned char)(fwu->flash_config_length >> 8);
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.transfer_length,
- length,
- sizeof(length));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write transfer length\n",
- __func__);
- return retval;
- }
-
- retval = fwu_write_f34_command(CMD_READ_CONFIG);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write command\n",
- __func__);
- return retval;
- }
-
- retval = fwu_wait_for_idle(WRITE_WAIT_MS, true);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to wait for idle status\n",
- __func__);
- return retval;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- base + fwu->off.payload,
- partition_table,
- fwu->partition_table_bytes);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read block data\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static int fwu_read_f34_v7_queries(void)
-{
- int retval;
- unsigned char ii;
- unsigned char base;
- unsigned char index;
- unsigned char offset;
- unsigned char *ptable;
- struct f34_v7_query_0 query_0;
- struct f34_v7_query_1_7 query_1_7;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f34_fd.query_base_addr;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- base,
- query_0.data,
- sizeof(query_0.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read query 0\n",
- __func__);
- return retval;
- }
-
- offset = query_0.subpacket_1_size + 1;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- base + offset,
- query_1_7.data,
- sizeof(query_1_7.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read queries 1 to 7\n",
- __func__);
- return retval;
- }
-
- fwu->bootloader_id[0] = query_1_7.bl_minor_revision;
- fwu->bootloader_id[1] = query_1_7.bl_major_revision;
-
- if (fwu->bootloader_id[1] == BL_V8)
- fwu->bl_version = BL_V8;
-
- fwu->block_size = query_1_7.block_size_15_8 << 8 |
- query_1_7.block_size_7_0;
-
- fwu->flash_config_length = query_1_7.flash_config_length_15_8 << 8 |
- query_1_7.flash_config_length_7_0;
-
- fwu->payload_length = query_1_7.payload_length_15_8 << 8 |
- query_1_7.payload_length_7_0;
-
- fwu->off.flash_status = V7_FLASH_STATUS_OFFSET;
- fwu->off.partition_id = V7_PARTITION_ID_OFFSET;
- fwu->off.block_number = V7_BLOCK_NUMBER_OFFSET;
- fwu->off.transfer_length = V7_TRANSFER_LENGTH_OFFSET;
- fwu->off.flash_cmd = V7_COMMAND_OFFSET;
- fwu->off.payload = V7_PAYLOAD_OFFSET;
-
- index = sizeof(query_1_7.data) - V7_PARTITION_SUPPORT_BYTES;
-
- fwu->partitions = 0;
- for (offset = 0; offset < V7_PARTITION_SUPPORT_BYTES; offset++) {
- for (ii = 0; ii < 8; ii++) {
- if (query_1_7.data[index + offset] & (1 << ii))
- fwu->partitions++;
- }
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Supported partitions: 0x%02x\n",
- __func__, query_1_7.data[index + offset]);
- }
-
- fwu->partition_table_bytes = fwu->partitions * 8 + 2;
-
- ptable = kzalloc(fwu->partition_table_bytes, GFP_KERNEL);
- if (!ptable) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for partition table\n",
- __func__);
- return -ENOMEM;
- }
-
- retval = fwu_read_f34_v7_partition_table(ptable);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read partition table\n",
- __func__);
- kfree(ptable);
- return retval;
- }
-
- fwu_parse_partition_table(ptable, &fwu->blkcount, &fwu->phyaddr);
-
- if (fwu->blkcount.dp_config)
- fwu->flash_properties.has_disp_config = 1;
- else
- fwu->flash_properties.has_disp_config = 0;
-
- if (fwu->blkcount.pm_config)
- fwu->flash_properties.has_pm_config = 1;
- else
- fwu->flash_properties.has_pm_config = 0;
-
- if (fwu->blkcount.bl_config)
- fwu->flash_properties.has_bl_config = 1;
- else
- fwu->flash_properties.has_bl_config = 0;
-
- if (fwu->blkcount.guest_code)
- fwu->has_guest_code = 1;
- else
- fwu->has_guest_code = 0;
-
- kfree(ptable);
-
- return 0;
-}
-
-static int fwu_read_f34_v5v6_queries(void)
-{
- int retval;
- unsigned char count;
- unsigned char base;
- unsigned char buf[10];
- struct f34_v5v6_flash_properties_2 properties_2;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f34_fd.query_base_addr;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- base + V5V6_BOOTLOADER_ID_OFFSET,
- fwu->bootloader_id,
- sizeof(fwu->bootloader_id));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read bootloader ID\n",
- __func__);
- return retval;
- }
-
- if (fwu->bl_version == BL_V5) {
- fwu->off.properties = V5_PROPERTIES_OFFSET;
- fwu->off.block_size = V5_BLOCK_SIZE_OFFSET;
- fwu->off.block_count = V5_BLOCK_COUNT_OFFSET;
- fwu->off.block_number = V5_BLOCK_NUMBER_OFFSET;
- fwu->off.payload = V5_BLOCK_DATA_OFFSET;
- } else if (fwu->bl_version == BL_V6) {
- fwu->off.properties = V6_PROPERTIES_OFFSET;
- fwu->off.properties_2 = V6_PROPERTIES_2_OFFSET;
- fwu->off.block_size = V6_BLOCK_SIZE_OFFSET;
- fwu->off.block_count = V6_BLOCK_COUNT_OFFSET;
- fwu->off.gc_block_count = V6_GUEST_CODE_BLOCK_COUNT_OFFSET;
- fwu->off.block_number = V6_BLOCK_NUMBER_OFFSET;
- fwu->off.payload = V6_BLOCK_DATA_OFFSET;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- base + fwu->off.block_size,
- buf,
- 2);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read block size info\n",
- __func__);
- return retval;
- }
-
- batohs(&fwu->block_size, &(buf[0]));
-
- if (fwu->bl_version == BL_V5) {
- fwu->off.flash_cmd = fwu->off.payload + fwu->block_size;
- fwu->off.flash_status = fwu->off.flash_cmd;
- } else if (fwu->bl_version == BL_V6) {
- fwu->off.flash_cmd = V6_FLASH_COMMAND_OFFSET;
- fwu->off.flash_status = V6_FLASH_STATUS_OFFSET;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- base + fwu->off.properties,
- fwu->flash_properties.data,
- sizeof(fwu->flash_properties.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read flash properties\n",
- __func__);
- return retval;
- }
-
- count = 4;
-
- if (fwu->flash_properties.has_pm_config)
- count += 2;
-
- if (fwu->flash_properties.has_bl_config)
- count += 2;
-
- if (fwu->flash_properties.has_disp_config)
- count += 2;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- base + fwu->off.block_count,
- buf,
- count);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read block count info\n",
- __func__);
- return retval;
- }
-
- batohs(&fwu->blkcount.ui_firmware, &(buf[0]));
- batohs(&fwu->blkcount.ui_config, &(buf[2]));
-
- count = 4;
-
- if (fwu->flash_properties.has_pm_config) {
- batohs(&fwu->blkcount.pm_config, &(buf[count]));
- count += 2;
- }
-
- if (fwu->flash_properties.has_bl_config) {
- batohs(&fwu->blkcount.bl_config, &(buf[count]));
- count += 2;
- }
-
- if (fwu->flash_properties.has_disp_config)
- batohs(&fwu->blkcount.dp_config, &(buf[count]));
-
- fwu->has_guest_code = false;
-
- if (fwu->flash_properties.has_query4) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- base + fwu->off.properties_2,
- properties_2.data,
- sizeof(properties_2.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read flash properties 2\n",
- __func__);
- return retval;
- }
-
- if (properties_2.has_guest_code) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- base + fwu->off.gc_block_count,
- buf,
- 2);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read guest code block count\n",
- __func__);
- return retval;
- }
-
- batohs(&fwu->blkcount.guest_code, &(buf[0]));
- fwu->has_guest_code = true;
- }
- }
-
- return 0;
-}
-
-static int fwu_read_f34_queries(void)
-{
- int retval;
-
- memset(&fwu->blkcount, 0x00, sizeof(fwu->blkcount));
- memset(&fwu->phyaddr, 0x00, sizeof(fwu->phyaddr));
-
- if (fwu->bl_version == BL_V7)
- retval = fwu_read_f34_v7_queries();
- else
- retval = fwu_read_f34_v5v6_queries();
-
- return retval;
-}
-
-static int fwu_write_f34_v7_blocks(unsigned char *block_ptr,
- unsigned short block_cnt, unsigned char command)
-{
- int retval;
- unsigned char base;
- unsigned char length[2];
- unsigned short transfer;
- unsigned short max_transfer;
- unsigned short remaining = block_cnt;
- unsigned short block_number = 0;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f34_fd.data_base_addr;
-
- retval = fwu_write_f34_partition_id(command);
- if (retval < 0)
- return retval;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.block_number,
- (unsigned char *)&block_number,
- sizeof(block_number));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write block number\n",
- __func__);
- return retval;
- }
-
- if (fwu->payload_length > (PAGE_SIZE / fwu->block_size))
- max_transfer = PAGE_SIZE / fwu->block_size;
- else
- max_transfer = fwu->payload_length;
-
- do {
- if (remaining / max_transfer)
- transfer = max_transfer;
- else
- transfer = remaining;
-
- length[0] = (unsigned char)(transfer & MASK_8BIT);
- length[1] = (unsigned char)(transfer >> 8);
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.transfer_length,
- length,
- sizeof(length));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write transfer length (%d blocks remaining)\n",
- __func__, remaining);
- return retval;
- }
-
- retval = fwu_write_f34_command(command);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write command (%d blocks remaining)\n",
- __func__, remaining);
- return retval;
- }
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.payload,
- block_ptr,
- transfer * fwu->block_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write block data (%d blocks remaining)\n",
- __func__, remaining);
- return retval;
- }
-
- retval = fwu_wait_for_idle(WRITE_WAIT_MS, false);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to wait for idle status (%d blocks remaining)\n",
- __func__, remaining);
- return retval;
- }
-
- block_ptr += (transfer * fwu->block_size);
- remaining -= transfer;
- } while (remaining);
-
- return 0;
-}
-
-static int fwu_write_f34_v5v6_blocks(unsigned char *block_ptr,
- unsigned short block_cnt, unsigned char command)
-{
- int retval;
- unsigned char base;
- unsigned char block_number[] = {0, 0};
- unsigned short blk;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f34_fd.data_base_addr;
-
- block_number[1] |= (fwu->config_area << 5);
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.block_number,
- block_number,
- sizeof(block_number));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write block number\n",
- __func__);
- return retval;
- }
-
- for (blk = 0; blk < block_cnt; blk++) {
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.payload,
- block_ptr,
- fwu->block_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write block data (block %d)\n",
- __func__, blk);
- return retval;
- }
-
- retval = fwu_write_f34_command(command);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write command for block %d\n",
- __func__, blk);
- return retval;
- }
-
- retval = fwu_wait_for_idle(WRITE_WAIT_MS, false);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to wait for idle status (block %d)\n",
- __func__, blk);
- return retval;
- }
-
- block_ptr += fwu->block_size;
- }
-
- return 0;
-}
-
-static int fwu_write_f34_blocks(unsigned char *block_ptr,
- unsigned short block_cnt, unsigned char cmd)
-{
- int retval;
-
- if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- retval = fwu_write_f34_v7_blocks(block_ptr, block_cnt, cmd);
- else
- retval = fwu_write_f34_v5v6_blocks(block_ptr, block_cnt, cmd);
-
- return retval;
-}
-
-static int fwu_read_f34_v7_blocks(unsigned short block_cnt,
- unsigned char command)
-{
- int retval;
- unsigned char base;
- unsigned char length[2];
- unsigned short transfer;
- unsigned short max_transfer;
- unsigned short remaining = block_cnt;
- unsigned short block_number = 0;
- unsigned short index = 0;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f34_fd.data_base_addr;
-
- retval = fwu_write_f34_partition_id(command);
- if (retval < 0)
- return retval;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.block_number,
- (unsigned char *)&block_number,
- sizeof(block_number));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write block number\n",
- __func__);
- return retval;
- }
-
- if (fwu->payload_length > (PAGE_SIZE / fwu->block_size))
- max_transfer = PAGE_SIZE / fwu->block_size;
- else
- max_transfer = fwu->payload_length;
-
- do {
- if (remaining / max_transfer)
- transfer = max_transfer;
- else
- transfer = remaining;
-
- length[0] = (unsigned char)(transfer & MASK_8BIT);
- length[1] = (unsigned char)(transfer >> 8);
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.transfer_length,
- length,
- sizeof(length));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write transfer length (%d blocks remaining)\n",
- __func__, remaining);
- return retval;
- }
-
- retval = fwu_write_f34_command(command);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write command (%d blocks remaining)\n",
- __func__, remaining);
- return retval;
- }
-
- retval = fwu_wait_for_idle(WRITE_WAIT_MS, false);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to wait for idle status (%d blocks remaining)\n",
- __func__, remaining);
- return retval;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- base + fwu->off.payload,
- &fwu->read_config_buf[index],
- transfer * fwu->block_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read block data (%d blocks remaining)\n",
- __func__, remaining);
- return retval;
- }
-
- index += (transfer * fwu->block_size);
- remaining -= transfer;
- } while (remaining);
-
- return 0;
-}
-
-static int fwu_read_f34_v5v6_blocks(unsigned short block_cnt,
- unsigned char command)
-{
- int retval;
- unsigned char base;
- unsigned char block_number[] = {0, 0};
- unsigned short blk;
- unsigned short index = 0;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f34_fd.data_base_addr;
-
- block_number[1] |= (fwu->config_area << 5);
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + fwu->off.block_number,
- block_number,
- sizeof(block_number));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write block number\n",
- __func__);
- return retval;
- }
-
- for (blk = 0; blk < block_cnt; blk++) {
- retval = fwu_write_f34_command(command);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write read config command\n",
- __func__);
- return retval;
- }
-
- retval = fwu_wait_for_idle(WRITE_WAIT_MS, false);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to wait for idle status\n",
- __func__);
- return retval;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- base + fwu->off.payload,
- &fwu->read_config_buf[index],
- fwu->block_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read block data (block %d)\n",
- __func__, blk);
- return retval;
- }
-
- index += fwu->block_size;
- }
-
- return 0;
-}
-
-static int fwu_read_f34_blocks(unsigned short block_cnt, unsigned char cmd)
-{
- int retval;
-
- if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- retval = fwu_read_f34_v7_blocks(block_cnt, cmd);
- else
- retval = fwu_read_f34_v5v6_blocks(block_cnt, cmd);
-
- return retval;
-}
-
-static int fwu_get_image_firmware_id(unsigned int *fw_id)
-{
- int retval;
- unsigned char index = 0;
- char *strptr;
- char *firmware_id;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- if (fwu->img.contains_firmware_id) {
- *fw_id = fwu->img.firmware_id;
- } else {
- strptr = strnstr(fwu->image_name, "PR", MAX_IMAGE_NAME_LEN);
- if (!strptr) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: No valid PR number (PRxxxxxxx) found in image file name (%s)\n",
- __func__, fwu->image_name);
- return -EINVAL;
- }
-
- strptr += 2;
- firmware_id = kzalloc(MAX_FIRMWARE_ID_LEN, GFP_KERNEL);
- if (!firmware_id) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for firmware_id\n",
- __func__);
- return -ENOMEM;
- }
- while ((index < MAX_FIRMWARE_ID_LEN - 1) && strptr[index] >= '0'
- && strptr[index] <= '9') {
- firmware_id[index] = strptr[index];
- index++;
- }
- firmware_id[index] = '\0';
-
- retval = sstrtoul(firmware_id, 10, (unsigned long *)fw_id);
- kfree(firmware_id);
- if (retval) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to obtain image firmware ID\n",
- __func__);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static int fwu_get_device_config_id(void)
-{
- int retval;
- unsigned char config_id_size;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- config_id_size = V7_CONFIG_ID_SIZE;
- else
- config_id_size = V5V6_CONFIG_ID_SIZE;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fwu->f34_fd.ctrl_base_addr,
- fwu->config_id,
- config_id_size);
- if (retval < 0)
- return retval;
-
- return 0;
-}
-
-static enum flash_area fwu_go_nogo(void)
-{
- int retval;
- enum flash_area flash_area = NONE;
- unsigned char ii;
- unsigned char config_id_size;
- unsigned int device_fw_id;
- unsigned int image_fw_id;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- if (fwu->force_update) {
- flash_area = UI_FIRMWARE;
- goto exit;
- }
-
- /* Update both UI and config if device is in bootloader mode */
- if (fwu->in_bl_mode) {
- flash_area = UI_FIRMWARE;
- goto exit;
- }
-
- /* Get device firmware ID */
- device_fw_id = rmi4_data->firmware_id;
- dev_info(rmi4_data->pdev->dev.parent,
- "%s: Device firmware ID = %d\n",
- __func__, device_fw_id);
-
- /* Get image firmware ID */
- retval = fwu_get_image_firmware_id(&image_fw_id);
- if (retval < 0) {
- flash_area = NONE;
- goto exit;
- }
- dev_info(rmi4_data->pdev->dev.parent,
- "%s: Image firmware ID = %d\n",
- __func__, image_fw_id);
-
- if (image_fw_id > device_fw_id) {
- flash_area = UI_FIRMWARE;
- goto exit;
- } else if (image_fw_id < device_fw_id) {
- dev_info(rmi4_data->pdev->dev.parent,
- "%s: Image firmware ID older than device firmware ID\n",
- __func__);
- flash_area = NONE;
- goto exit;
- }
-
- /* Get device config ID */
- retval = fwu_get_device_config_id();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read device config ID\n",
- __func__);
- flash_area = NONE;
- goto exit;
- }
-
- if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8)
- config_id_size = V7_CONFIG_ID_SIZE;
- else
- config_id_size = V5V6_CONFIG_ID_SIZE;
-
- for (ii = 0; ii < config_id_size; ii++) {
- if (fwu->img.ui_config.data[ii] > fwu->config_id[ii]) {
- flash_area = UI_CONFIG;
- goto exit;
- } else if (fwu->img.ui_config.data[ii] < fwu->config_id[ii]) {
- flash_area = NONE;
- goto exit;
- }
- }
-
- flash_area = NONE;
-
-exit:
- if (flash_area == NONE) {
- dev_info(rmi4_data->pdev->dev.parent,
- "%s: No need to do reflash\n",
- __func__);
- } else {
- dev_info(rmi4_data->pdev->dev.parent,
- "%s: Updating %s\n",
- __func__,
- flash_area == UI_FIRMWARE ?
- "UI firmware and config" :
- "UI config only");
- }
-
- return flash_area;
-}
-
-static int fwu_scan_pdt(void)
-{
- int retval;
- unsigned char ii;
- unsigned char intr_count = 0;
- unsigned char intr_off;
- unsigned char intr_src;
- unsigned short addr;
- bool f01found = false;
- bool f34found = false;
- bool f35found = false;
- struct synaptics_rmi4_fn_desc rmi_fd;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- fwu->in_ub_mode = false;
-
- for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- addr,
- (unsigned char *)&rmi_fd,
- sizeof(rmi_fd));
- if (retval < 0)
- return retval;
-
- if (rmi_fd.fn_number) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Found F%02x\n",
- __func__, rmi_fd.fn_number);
- switch (rmi_fd.fn_number) {
- case SYNAPTICS_RMI4_F01:
- f01found = true;
-
- rmi4_data->f01_query_base_addr =
- rmi_fd.query_base_addr;
- rmi4_data->f01_ctrl_base_addr =
- rmi_fd.ctrl_base_addr;
- rmi4_data->f01_data_base_addr =
- rmi_fd.data_base_addr;
- rmi4_data->f01_cmd_base_addr =
- rmi_fd.cmd_base_addr;
- break;
- case SYNAPTICS_RMI4_F34:
- f34found = true;
- fwu->f34_fd.query_base_addr =
- rmi_fd.query_base_addr;
- fwu->f34_fd.ctrl_base_addr =
- rmi_fd.ctrl_base_addr;
- fwu->f34_fd.data_base_addr =
- rmi_fd.data_base_addr;
-
- switch (rmi_fd.fn_version) {
- case F34_V0:
- fwu->bl_version = BL_V5;
- break;
- case F34_V1:
- fwu->bl_version = BL_V6;
- break;
- case F34_V2:
- fwu->bl_version = BL_V7;
- break;
- default:
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Unrecognized F34 version\n",
- __func__);
- return -EINVAL;
- }
-
- fwu->intr_mask = 0;
- intr_src = rmi_fd.intr_src_count;
- intr_off = intr_count % 8;
- for (ii = intr_off;
- ii < (intr_src + intr_off);
- ii++) {
- fwu->intr_mask |= 1 << ii;
- }
- break;
- case SYNAPTICS_RMI4_F35:
- f35found = true;
- fwu->f35_fd.query_base_addr =
- rmi_fd.query_base_addr;
- fwu->f35_fd.ctrl_base_addr =
- rmi_fd.ctrl_base_addr;
- fwu->f35_fd.data_base_addr =
- rmi_fd.data_base_addr;
- break;
- }
- } else {
- break;
- }
-
- intr_count += rmi_fd.intr_src_count;
- }
-
- if (!f01found || !f34found) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to find both F01 and F34\n",
- __func__);
- if (!f35found) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to find F35\n",
- __func__);
- return -EINVAL;
- } else {
- fwu->in_ub_mode = true;
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: In microbootloader mode\n",
- __func__);
- fwu_recovery_check_status();
- return 0;
- }
- }
-
- rmi4_data->intr_mask[0] |= fwu->intr_mask;
-
- addr = rmi4_data->f01_ctrl_base_addr + 1;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- addr,
- &(rmi4_data->intr_mask[0]),
- sizeof(rmi4_data->intr_mask[0]));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set interrupt enable bit\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static int fwu_enter_flash_prog(void)
-{
- int retval;
- struct f01_device_control f01_device_control;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- retval = fwu_read_flash_status();
- if (retval < 0)
- return retval;
-
- if (fwu->in_bl_mode)
- return 0;
-
- retval = rmi4_data->irq_enable(rmi4_data, false, true);
- if (retval < 0)
- return retval;
-
- msleep(INT_DISABLE_WAIT_MS);
-
- retval = fwu_write_f34_command(CMD_ENABLE_FLASH_PROG);
- if (retval < 0)
- return retval;
-
- retval = fwu_wait_for_idle(ENABLE_WAIT_MS, false);
- if (retval < 0)
- return retval;
-
- if (!fwu->in_bl_mode) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: BL mode not entered\n",
- __func__);
- return -EINVAL;
- }
-
- if (rmi4_data->hw_if->bl_hw_init) {
- retval = rmi4_data->hw_if->bl_hw_init(rmi4_data);
- if (retval < 0)
- return retval;
- }
-
- retval = fwu_scan_pdt();
- if (retval < 0)
- return retval;
-
- retval = fwu_read_f34_queries();
- if (retval < 0)
- return retval;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_ctrl_base_addr,
- f01_device_control.data,
- sizeof(f01_device_control.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read F01 device control\n",
- __func__);
- return retval;
- }
-
- f01_device_control.nosleep = true;
- f01_device_control.sleep_mode = SLEEP_MODE_NORMAL;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- rmi4_data->f01_ctrl_base_addr,
- f01_device_control.data,
- sizeof(f01_device_control.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write F01 device control\n",
- __func__);
- return retval;
- }
-
- msleep(ENTER_FLASH_PROG_WAIT_MS);
-
- return retval;
-}
-
-static int fwu_check_ui_firmware_size(void)
-{
- unsigned short block_count;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- block_count = fwu->img.ui_firmware.size / fwu->block_size;
-
- if (block_count != fwu->blkcount.ui_firmware) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: UI firmware size mismatch\n",
- __func__);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int fwu_check_ui_configuration_size(void)
-{
- unsigned short block_count;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- block_count = fwu->img.ui_config.size / fwu->block_size;
-
- if (block_count != fwu->blkcount.ui_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: UI configuration size mismatch\n",
- __func__);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int fwu_check_dp_configuration_size(void)
-{
- unsigned short block_count;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- block_count = fwu->img.dp_config.size / fwu->block_size;
-
- if (block_count != fwu->blkcount.dp_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Display configuration size mismatch\n",
- __func__);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int fwu_check_pm_configuration_size(void)
-{
- unsigned short block_count;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- block_count = fwu->img.pm_config.size / fwu->block_size;
-
- if (block_count != fwu->blkcount.pm_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Permanent configuration size mismatch\n",
- __func__);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int fwu_check_bl_configuration_size(void)
-{
- unsigned short block_count;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- block_count = fwu->img.bl_config.size / fwu->block_size;
-
- if (block_count != fwu->blkcount.bl_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Bootloader configuration size mismatch\n",
- __func__);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int fwu_check_guest_code_size(void)
-{
- unsigned short block_count;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- block_count = fwu->img.guest_code.size / fwu->block_size;
- if (block_count != fwu->blkcount.guest_code) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Guest code size mismatch\n",
- __func__);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int fwu_write_firmware(void)
-{
- unsigned short firmware_block_count;
-
- firmware_block_count = fwu->img.ui_firmware.size / fwu->block_size;
-
- return fwu_write_f34_blocks((unsigned char *)fwu->img.ui_firmware.data,
- firmware_block_count, CMD_WRITE_FW);
-}
-
-static int fwu_erase_configuration(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- switch (fwu->config_area) {
- case UI_CONFIG_AREA:
- retval = fwu_write_f34_command(CMD_ERASE_UI_CONFIG);
- if (retval < 0)
- return retval;
- break;
- case DP_CONFIG_AREA:
- retval = fwu_write_f34_command(CMD_ERASE_DISP_CONFIG);
- if (retval < 0)
- return retval;
- break;
- case BL_CONFIG_AREA:
- retval = fwu_write_f34_command(CMD_ERASE_BL_CONFIG);
- if (retval < 0)
- return retval;
- break;
- }
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Erase command written\n",
- __func__);
-
- retval = fwu_wait_for_idle(ERASE_WAIT_MS, false);
- if (retval < 0)
- return retval;
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Idle status detected\n",
- __func__);
-
- return retval;
-}
-
-static int fwu_erase_guest_code(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- retval = fwu_write_f34_command(CMD_ERASE_GUEST_CODE);
- if (retval < 0)
- return retval;
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Erase command written\n",
- __func__);
-
- retval = fwu_wait_for_idle(ERASE_WAIT_MS, false);
- if (retval < 0)
- return retval;
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Idle status detected\n",
- __func__);
-
- return 0;
-}
-
-static int fwu_erase_all(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- if (fwu->bl_version == BL_V7) {
- retval = fwu_write_f34_command(CMD_ERASE_UI_FIRMWARE);
- if (retval < 0)
- return retval;
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Erase command written\n",
- __func__);
-
- retval = fwu_wait_for_idle(ERASE_WAIT_MS, false);
- if (retval < 0)
- return retval;
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Idle status detected\n",
- __func__);
-
- fwu->config_area = UI_CONFIG_AREA;
- retval = fwu_erase_configuration();
- if (retval < 0)
- return retval;
- } else {
- retval = fwu_write_f34_command(CMD_ERASE_ALL);
- if (retval < 0)
- return retval;
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Erase all command written\n",
- __func__);
-
- retval = fwu_wait_for_idle(ERASE_WAIT_MS, false);
- if (!(fwu->bl_version == BL_V8 &&
- fwu->flash_status == BAD_PARTITION_TABLE)) {
- if (retval < 0)
- return retval;
- }
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Idle status detected\n",
- __func__);
-
- if (fwu->bl_version == BL_V8)
- return 0;
- }
-
- if (fwu->flash_properties.has_disp_config &&
- fwu->img.contains_disp_config) {
- fwu->config_area = DP_CONFIG_AREA;
- retval = fwu_erase_configuration();
- if (retval < 0)
- return retval;
- }
-
- if (fwu->has_guest_code && fwu->img.contains_guest_code) {
- retval = fwu_erase_guest_code();
- if (retval < 0)
- return retval;
- }
-
- return 0;
-}
-
-static int fwu_write_configuration(void)
-{
- return fwu_write_f34_blocks((unsigned char *)fwu->config_data,
- fwu->config_block_count, CMD_WRITE_CONFIG);
-}
-
-static int fwu_write_ui_configuration(void)
-{
- fwu->config_area = UI_CONFIG_AREA;
- fwu->config_data = fwu->img.ui_config.data;
- fwu->config_size = fwu->img.ui_config.size;
- fwu->config_block_count = fwu->config_size / fwu->block_size;
-
- return fwu_write_configuration();
-}
-
-static int fwu_write_dp_configuration(void)
-{
- fwu->config_area = DP_CONFIG_AREA;
- fwu->config_data = fwu->img.dp_config.data;
- fwu->config_size = fwu->img.dp_config.size;
- fwu->config_block_count = fwu->config_size / fwu->block_size;
-
- return fwu_write_configuration();
-}
-
-static int fwu_write_pm_configuration(void)
-{
- fwu->config_area = PM_CONFIG_AREA;
- fwu->config_data = fwu->img.pm_config.data;
- fwu->config_size = fwu->img.pm_config.size;
- fwu->config_block_count = fwu->config_size / fwu->block_size;
-
- return fwu_write_configuration();
-}
-
-static int fwu_write_flash_configuration(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- fwu->config_area = FLASH_CONFIG_AREA;
- fwu->config_data = fwu->img.fl_config.data;
- fwu->config_size = fwu->img.fl_config.size;
- fwu->config_block_count = fwu->config_size / fwu->block_size;
-
- if (fwu->config_block_count != fwu->blkcount.fl_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Flash configuration size mismatch\n",
- __func__);
- return -EINVAL;
- }
-
- retval = fwu_write_f34_command(CMD_ERASE_FLASH_CONFIG);
- if (retval < 0)
- return retval;
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Erase flash configuration command written\n",
- __func__);
-
- retval = fwu_wait_for_idle(ERASE_WAIT_MS, false);
- if (retval < 0)
- return retval;
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Idle status detected\n",
- __func__);
-
- retval = fwu_write_configuration();
- if (retval < 0)
- return retval;
-
- rmi4_data->reset_device(rmi4_data, false);
-
- return 0;
-}
-
-static int fwu_write_guest_code(void)
-{
- int retval;
- unsigned short guest_code_block_count;
-
- guest_code_block_count = fwu->img.guest_code.size / fwu->block_size;
-
- retval = fwu_write_f34_blocks((unsigned char *)fwu->img.guest_code.data,
- guest_code_block_count, CMD_WRITE_GUEST_CODE);
- if (retval < 0)
- return retval;
-
- return 0;
-}
-
-static int fwu_write_lockdown(void)
-{
- unsigned short lockdown_block_count;
-
- lockdown_block_count = fwu->img.lockdown.size / fwu->block_size;
-
- return fwu_write_f34_blocks((unsigned char *)fwu->img.lockdown.data,
- lockdown_block_count, CMD_WRITE_LOCKDOWN);
-}
-
-static int fwu_write_partition_table_v8(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- fwu->config_area = FLASH_CONFIG_AREA;
- fwu->config_data = fwu->img.fl_config.data;
- fwu->config_size = fwu->img.fl_config.size;
- fwu->config_block_count = fwu->config_size / fwu->block_size;
-
- if (fwu->config_block_count != fwu->blkcount.fl_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Flash configuration size mismatch\n",
- __func__);
- return -EINVAL;
- }
-
- retval = fwu_write_configuration();
- if (retval < 0)
- return retval;
-
- rmi4_data->reset_device(rmi4_data, false);
-
- return 0;
-}
-
-static int fwu_write_partition_table_v7(void)
-{
- int retval;
- unsigned short block_count;
-
- block_count = fwu->blkcount.bl_config;
- fwu->config_area = BL_CONFIG_AREA;
- fwu->config_size = fwu->block_size * block_count;
-
- retval = fwu_allocate_read_config_buf(fwu->config_size);
- if (retval < 0)
- return retval;
-
- retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG);
- if (retval < 0)
- return retval;
-
- retval = fwu_erase_configuration();
- if (retval < 0)
- return retval;
-
- retval = fwu_write_flash_configuration();
- if (retval < 0)
- return retval;
-
- fwu->config_area = BL_CONFIG_AREA;
- fwu->config_data = fwu->read_config_buf;
- fwu->config_size = fwu->img.bl_config.size;
- fwu->config_block_count = fwu->config_size / fwu->block_size;
-
- retval = fwu_write_configuration();
- if (retval < 0)
- return retval;
-
- return 0;
-}
-
-static int fwu_do_reflash(void)
-{
- int retval;
-
- if (!fwu->new_partition_table) {
- retval = fwu_check_ui_firmware_size();
- if (retval < 0)
- return retval;
-
- retval = fwu_check_ui_configuration_size();
- if (retval < 0)
- return retval;
-
- if (fwu->flash_properties.has_disp_config &&
- fwu->img.contains_disp_config) {
- retval = fwu_check_dp_configuration_size();
- if (retval < 0)
- return retval;
- }
-
- if (fwu->has_guest_code && fwu->img.contains_guest_code) {
- retval = fwu_check_guest_code_size();
- if (retval < 0)
- return retval;
- }
- } else if (fwu->bl_version == BL_V7) {
- retval = fwu_check_bl_configuration_size();
- if (retval < 0)
- return retval;
- }
-
- retval = fwu_erase_all();
- if (retval < 0)
- return retval;
-
- if (fwu->bl_version == BL_V7 && fwu->new_partition_table) {
- retval = fwu_write_partition_table_v7();
- if (retval < 0)
- return retval;
- pr_notice("%s: Partition table programmed\n", __func__);
- } else if (fwu->bl_version == BL_V8) {
- retval = fwu_write_partition_table_v8();
- if (retval < 0)
- return retval;
- pr_notice("%s: Partition table programmed\n", __func__);
- }
-
- retval = fwu_write_firmware();
- if (retval < 0)
- return retval;
- pr_notice("%s: Firmware programmed\n", __func__);
-
- fwu->config_area = UI_CONFIG_AREA;
- retval = fwu_write_ui_configuration();
- if (retval < 0)
- return retval;
- pr_notice("%s: Configuration programmed\n", __func__);
-
- if (fwu->flash_properties.has_disp_config &&
- fwu->img.contains_disp_config) {
- retval = fwu_write_dp_configuration();
- if (retval < 0)
- return retval;
- pr_notice("%s: Display configuration programmed\n", __func__);
- }
-
- if (fwu->has_guest_code && fwu->img.contains_guest_code) {
- retval = fwu_write_guest_code();
- if (retval < 0)
- return retval;
- pr_notice("%s: Guest code programmed\n", __func__);
- }
-
- return retval;
-}
-
-static int fwu_do_read_config(void)
-{
- int retval;
- unsigned short block_count;
- unsigned short config_area;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- switch (fwu->config_area) {
- case UI_CONFIG_AREA:
- block_count = fwu->blkcount.ui_config;
- break;
- case DP_CONFIG_AREA:
- if (!fwu->flash_properties.has_disp_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Display configuration not supported\n",
- __func__);
- return -EINVAL;
- }
- block_count = fwu->blkcount.dp_config;
- break;
- case PM_CONFIG_AREA:
- if (!fwu->flash_properties.has_pm_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Permanent configuration not supported\n",
- __func__);
- return -EINVAL;
- }
- block_count = fwu->blkcount.pm_config;
- break;
- case BL_CONFIG_AREA:
- if (!fwu->flash_properties.has_bl_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Bootloader configuration not supported\n",
- __func__);
- return -EINVAL;
- }
- block_count = fwu->blkcount.bl_config;
- break;
- default:
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Invalid config area\n",
- __func__);
- return -EINVAL;
- }
-
- if (block_count == 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Invalid block count\n",
- __func__);
- return -EINVAL;
- }
-
- mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
-
- config_area = fwu->config_area;
-
- retval = fwu_enter_flash_prog();
- if (retval < 0)
- goto exit;
-
- fwu->config_area = config_area;
-
- fwu->config_size = fwu->block_size * block_count;
-
- retval = fwu_allocate_read_config_buf(fwu->config_size);
- if (retval < 0)
- goto exit;
-
- retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG);
-
-exit:
- rmi4_data->reset_device(rmi4_data, false);
-
- mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
-
- return retval;
-}
-
-static int fwu_do_lockdown_v7(void)
-{
- int retval;
- struct f34_v7_data0 status;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- retval = fwu_enter_flash_prog();
- if (retval < 0)
- return retval;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fwu->f34_fd.data_base_addr + fwu->off.flash_status,
- status.data,
- sizeof(status.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read flash status\n",
- __func__);
- return retval;
- }
-
- if (status.device_cfg_status == 2) {
- dev_info(rmi4_data->pdev->dev.parent,
- "%s: Device already locked down\n",
- __func__);
- return 0;
- }
-
- retval = fwu_write_lockdown();
- if (retval < 0)
- return retval;
-
- pr_notice("%s: Lockdown programmed\n", __func__);
-
- return retval;
-}
-
-static int fwu_do_lockdown_v5v6(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- retval = fwu_enter_flash_prog();
- if (retval < 0)
- return retval;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- fwu->f34_fd.query_base_addr + fwu->off.properties,
- fwu->flash_properties.data,
- sizeof(fwu->flash_properties.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read flash properties\n",
- __func__);
- return retval;
- }
-
- if (fwu->flash_properties.unlocked == 0) {
- dev_info(rmi4_data->pdev->dev.parent,
- "%s: Device already locked down\n",
- __func__);
- return 0;
- }
-
- retval = fwu_write_lockdown();
- if (retval < 0)
- return retval;
-
- pr_notice("%s: Lockdown programmed\n", __func__);
-
- return retval;
-}
-
-static int fwu_start_write_guest_code(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- retval = fwu_parse_image_info();
- if (retval < 0)
- return -EINVAL;
-
- if (!fwu->has_guest_code) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Guest code not supported\n",
- __func__);
- return -EINVAL;
- }
-
- if (!fwu->img.contains_guest_code) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: No guest code in firmware image\n",
- __func__);
- return -EINVAL;
- }
-
- if (rmi4_data->sensor_sleep) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Sensor sleeping\n",
- __func__);
- return -ENODEV;
- }
-
- rmi4_data->stay_awake = true;
-
- mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
-
- pr_notice("%s: Start of write guest code process\n", __func__);
-
- retval = fwu_enter_flash_prog();
- if (retval < 0)
- goto exit;
-
- retval = fwu_check_guest_code_size();
- if (retval < 0)
- goto exit;
-
- retval = fwu_erase_guest_code();
- if (retval < 0)
- goto exit;
-
- retval = fwu_write_guest_code();
- if (retval < 0)
- goto exit;
-
- pr_notice("%s: Guest code programmed\n", __func__);
-
-exit:
- rmi4_data->reset_device(rmi4_data, false);
-
- pr_notice("%s: End of write guest code process\n", __func__);
-
- mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
-
- rmi4_data->stay_awake = false;
-
- return retval;
-}
-
-static int fwu_start_write_config(void)
-{
- int retval;
- unsigned short config_area;
- unsigned int device_fw_id;
- unsigned int image_fw_id;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- retval = fwu_parse_image_info();
- if (retval < 0)
- return -EINVAL;
-
- switch (fwu->config_area) {
- case UI_CONFIG_AREA:
- device_fw_id = rmi4_data->firmware_id;
- retval = fwu_get_image_firmware_id(&image_fw_id);
- if (retval < 0)
- return retval;
- if (device_fw_id != image_fw_id) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Device and image firmware IDs don't match\n",
- __func__);
- return -EINVAL;
- }
- retval = fwu_check_ui_configuration_size();
- if (retval < 0)
- return retval;
- break;
- case DP_CONFIG_AREA:
- if (!fwu->flash_properties.has_disp_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Display configuration not supported\n",
- __func__);
- return -EINVAL;
- }
- if (!fwu->img.contains_disp_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: No display configuration in firmware image\n",
- __func__);
- return -EINVAL;
- }
- retval = fwu_check_dp_configuration_size();
- if (retval < 0)
- return retval;
- break;
- case PM_CONFIG_AREA:
- if (!fwu->flash_properties.has_pm_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Permanent configuration not supported\n",
- __func__);
- return -EINVAL;
- }
- if (!fwu->img.contains_perm_config) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: No permanent configuration in firmware image\n",
- __func__);
- return -EINVAL;
- }
- retval = fwu_check_pm_configuration_size();
- if (retval < 0)
- return retval;
- break;
- default:
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Configuration not supported\n",
- __func__);
- return -EINVAL;
- }
-
- if (rmi4_data->sensor_sleep) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Sensor sleeping\n",
- __func__);
- return -ENODEV;
- }
-
- rmi4_data->stay_awake = true;
-
- mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
-
- pr_notice("%s: Start of write config process\n", __func__);
-
- config_area = fwu->config_area;
-
- retval = fwu_enter_flash_prog();
- if (retval < 0)
- goto exit;
-
- fwu->config_area = config_area;
-
- if (fwu->config_area != PM_CONFIG_AREA) {
- retval = fwu_erase_configuration();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to erase config\n",
- __func__);
- goto exit;
- }
- }
-
- switch (fwu->config_area) {
- case UI_CONFIG_AREA:
- retval = fwu_write_ui_configuration();
- if (retval < 0)
- goto exit;
- break;
- case DP_CONFIG_AREA:
- retval = fwu_write_dp_configuration();
- if (retval < 0)
- goto exit;
- break;
- case PM_CONFIG_AREA:
- retval = fwu_write_pm_configuration();
- if (retval < 0)
- goto exit;
- break;
- }
-
- pr_notice("%s: Config written\n", __func__);
-
-exit:
- switch (fwu->config_area) {
- case UI_CONFIG_AREA:
- rmi4_data->reset_device(rmi4_data, true);
- break;
- case DP_CONFIG_AREA:
- case PM_CONFIG_AREA:
- rmi4_data->reset_device(rmi4_data, false);
- break;
- }
-
- pr_notice("%s: End of write config process\n", __func__);
-
- mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
-
- rmi4_data->stay_awake = false;
-
- return retval;
-}
-
-static int fwu_start_reflash(void)
-{
- int retval = 0;
- enum flash_area flash_area;
- const struct firmware *fw_entry = NULL;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- if (rmi4_data->sensor_sleep) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Sensor sleeping\n",
- __func__);
- return -ENODEV;
- }
-
- rmi4_data->stay_awake = true;
-
- mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
-
- pr_notice("%s: Start of reflash process\n", __func__);
-
- if (fwu->image == NULL) {
- retval = secure_memcpy(fwu->image_name, MAX_IMAGE_NAME_LEN,
- FW_IMAGE_NAME, sizeof(FW_IMAGE_NAME),
- sizeof(FW_IMAGE_NAME));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy image file name\n",
- __func__);
- goto exit;
- }
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Requesting firmware image %s\n",
- __func__, fwu->image_name);
-
- retval = request_firmware(&fw_entry, fwu->image_name,
- rmi4_data->pdev->dev.parent);
- if (retval != 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Firmware image %s not available\n",
- __func__, fwu->image_name);
- retval = -EINVAL;
- goto exit;
- }
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Firmware image size = %d\n",
- __func__, (unsigned int)fw_entry->size);
-
- fwu->image = fw_entry->data;
- }
-
- retval = fwu_parse_image_info();
- if (retval < 0)
- goto exit;
-
- if (fwu->blkcount.total_count != fwu->img.blkcount.total_count) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Flash size mismatch\n",
- __func__);
- retval = -EINVAL;
- goto exit;
- }
-
- if (fwu->bl_version != fwu->img.bl_version) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Bootloader version mismatch\n",
- __func__);
- retval = -EINVAL;
- goto exit;
- }
-
- if (!fwu->force_update && fwu->new_partition_table) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Partition table mismatch\n",
- __func__);
- retval = -EINVAL;
- goto exit;
- }
-
- retval = fwu_read_flash_status();
- if (retval < 0)
- goto exit;
-
- if (fwu->in_bl_mode) {
- dev_info(rmi4_data->pdev->dev.parent,
- "%s: Device in bootloader mode\n",
- __func__);
- }
-
- flash_area = fwu_go_nogo();
-
- if (flash_area != NONE) {
- retval = fwu_enter_flash_prog();
- if (retval < 0) {
- rmi4_data->reset_device(rmi4_data, false);
- goto exit;
- }
- }
-
- switch (flash_area) {
- case UI_FIRMWARE:
- retval = fwu_do_reflash();
- rmi4_data->reset_device(rmi4_data, true);
- break;
- case UI_CONFIG:
- retval = fwu_check_ui_configuration_size();
- if (retval < 0)
- break;
- fwu->config_area = UI_CONFIG_AREA;
- retval = fwu_erase_configuration();
- if (retval < 0)
- break;
- retval = fwu_write_ui_configuration();
- rmi4_data->reset_device(rmi4_data, true);
- break;
- case NONE:
- default:
- rmi4_data->reset_device(rmi4_data, false);
- break;
- }
-
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to do reflash\n",
- __func__);
- goto exit;
- }
-
- if (fwu->do_lockdown && (fwu->img.lockdown.data != NULL)) {
- switch (fwu->bl_version) {
- case BL_V5:
- case BL_V6:
- retval = fwu_do_lockdown_v5v6();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to do lockdown\n",
- __func__);
- }
- rmi4_data->reset_device(rmi4_data, false);
- break;
- case BL_V7:
- case BL_V8:
- retval = fwu_do_lockdown_v7();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to do lockdown\n",
- __func__);
- }
- rmi4_data->reset_device(rmi4_data, false);
- break;
- default:
- break;
- }
- }
-
-exit:
- if (fw_entry)
- release_firmware(fw_entry);
-
- pr_notice("%s: End of reflash process\n", __func__);
-
- mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
-
- rmi4_data->stay_awake = false;
-
- return retval;
-}
-
-static int fwu_recovery_check_status(void)
-{
- int retval;
- unsigned char base;
- unsigned char status;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f35_fd.data_base_addr;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- base + F35_ERROR_CODE_OFFSET,
- &status,
- 1);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read status\n",
- __func__);
- return retval;
- }
-
- status = status & MASK_7BIT;
-
- if (status != 0x00) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Recovery mode status = %d\n",
- __func__, status);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int fwu_recovery_erase_all(void)
-{
- int retval;
- unsigned char base;
- unsigned char command = CMD_F35_ERASE_ALL;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f35_fd.ctrl_base_addr;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + F35_CHUNK_COMMAND_OFFSET,
- &command,
- sizeof(command));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to issue erase all command\n",
- __func__);
- return retval;
- }
-
- msleep(F35_ERASE_ALL_WAIT_MS);
-
- retval = fwu_recovery_check_status();
- if (retval < 0)
- return retval;
-
- return 0;
-}
-
-static int fwu_recovery_write_chunk(void)
-{
- int retval;
- unsigned char base;
- unsigned char chunk_number[] = {0, 0};
- unsigned char chunk_spare;
- unsigned char chunk_size;
- unsigned char buf[F35_CHUNK_SIZE + 1];
- unsigned short chunk;
- unsigned short chunk_total;
- unsigned short bytes_written = 0;
- unsigned char *chunk_ptr = (unsigned char *)fwu->image;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f35_fd.ctrl_base_addr;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + F35_CHUNK_NUM_LSB_OFFSET,
- chunk_number,
- sizeof(chunk_number));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write chunk number\n",
- __func__);
- return retval;
- }
-
- buf[sizeof(buf) - 1] = CMD_F35_WRITE_CHUNK;
-
- chunk_total = fwu->image_size / F35_CHUNK_SIZE;
- chunk_spare = fwu->image_size % F35_CHUNK_SIZE;
- if (chunk_spare)
- chunk_total++;
-
- for (chunk = 0; chunk < chunk_total; chunk++) {
- if (chunk_spare && chunk == chunk_total - 1)
- chunk_size = chunk_spare;
- else
- chunk_size = F35_CHUNK_SIZE;
-
- memset(buf, 0x00, F35_CHUNK_SIZE);
- secure_memcpy(buf, sizeof(buf), chunk_ptr,
- fwu->image_size - bytes_written,
- chunk_size);
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + F35_CHUNK_DATA_OFFSET,
- buf,
- sizeof(buf));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write chunk data (chunk %d)\n",
- __func__, chunk);
- return retval;
- }
- chunk_ptr += chunk_size;
- bytes_written += chunk_size;
- }
-
- retval = fwu_recovery_check_status();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write chunk data\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static int fwu_recovery_reset(void)
-{
- int retval;
- unsigned char base;
- unsigned char command = CMD_F35_RESET;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- base = fwu->f35_fd.ctrl_base_addr;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- base + F35_CHUNK_COMMAND_OFFSET,
- &command,
- sizeof(command));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to issue reset command\n",
- __func__);
- return retval;
- }
-
- msleep(F35_RESET_WAIT_MS);
-
- return 0;
-}
-
-static int fwu_start_recovery(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- if (rmi4_data->sensor_sleep) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Sensor sleeping\n",
- __func__);
- return -ENODEV;
- }
-
- rmi4_data->stay_awake = true;
-
- mutex_lock(&rmi4_data->rmi4_exp_init_mutex);
-
- pr_notice("%s: Start of recovery process\n", __func__);
-
- retval = rmi4_data->irq_enable(rmi4_data, false, false);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to disable interrupt\n",
- __func__);
- goto exit;
- }
-
- retval = fwu_recovery_erase_all();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to do erase all in recovery mode\n",
- __func__);
- goto exit;
- }
-
- pr_notice("%s: External flash erased\n", __func__);
-
- retval = fwu_recovery_write_chunk();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write chunk data in recovery mode\n",
- __func__);
- goto exit;
- }
-
- pr_notice("%s: Chunk data programmed\n", __func__);
-
- retval = fwu_recovery_reset();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to reset device in recovery mode\n",
- __func__);
- goto exit;
- }
-
- pr_notice("%s: Recovery mode reset issued\n", __func__);
-
- rmi4_data->reset_device(rmi4_data, true);
-
- retval = 0;
-
-exit:
- pr_notice("%s: End of recovery process\n", __func__);
-
- mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);
-
- rmi4_data->stay_awake = false;
-
- return retval;
-}
-
-int synaptics_fw_updater(const unsigned char *fw_data)
-{
- int retval;
-
- if (!fwu)
- return -ENODEV;
-
- if (!fwu->initialized)
- return -ENODEV;
-
- if (fwu->in_ub_mode)
- return -ENODEV;
-
- fwu->image = fw_data;
-
- retval = fwu_start_reflash();
-
- fwu->image = NULL;
-
- return retval;
-}
-EXPORT_SYMBOL(synaptics_fw_updater);
-
-#ifdef DO_STARTUP_FW_UPDATE
-static void fwu_startup_fw_update_work(struct work_struct *work)
-{
- static unsigned char do_once = 1;
-#ifdef WAIT_FOR_FB_READY
- unsigned int timeout;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-#endif
-
- if (!do_once)
- return;
- do_once = 0;
-
-#ifdef WAIT_FOR_FB_READY
- timeout = FB_READY_TIMEOUT_S * 1000 / FB_READY_WAIT_MS + 1;
-
- while (!rmi4_data->fb_ready) {
- msleep(FB_READY_WAIT_MS);
- timeout--;
- if (timeout == 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Timed out waiting for FB ready\n",
- __func__);
- return;
- }
- }
-#endif
-
- synaptics_fw_updater(NULL);
-
- return;
-}
-#endif
-
-static ssize_t fwu_sysfs_show_image(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- if (count < fwu->config_size) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Not enough space (%d bytes) in buffer\n",
- __func__, (unsigned int)count);
- return -EINVAL;
- }
-
- retval = secure_memcpy(buf, count, fwu->read_config_buf,
- fwu->read_config_buf_size, fwu->config_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy config data\n",
- __func__);
- return retval;
- }
-
- return fwu->config_size;
-}
-
-static ssize_t fwu_sysfs_store_image(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- retval = secure_memcpy(&fwu->ext_data_source[fwu->data_pos],
- fwu->image_size - fwu->data_pos, buf, count, count);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy image data\n",
- __func__);
- return retval;
- }
-
- fwu->data_pos += count;
-
- return count;
-}
-
-static ssize_t fwu_sysfs_do_recovery_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- if (sscanf(buf, "%u", &input) != 1) {
- retval = -EINVAL;
- goto exit;
- }
-
- if (!fwu->in_ub_mode) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Not in microbootloader mode\n",
- __func__);
- retval = -EINVAL;
- goto exit;
- }
-
- if (!fwu->ext_data_source)
- return -EINVAL;
- else
- fwu->image = fwu->ext_data_source;
-
- retval = fwu_start_recovery();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to do recovery\n",
- __func__);
- goto exit;
- }
-
- retval = count;
-
-exit:
- kfree(fwu->ext_data_source);
- fwu->ext_data_source = NULL;
- fwu->image = NULL;
- return retval;
-}
-
-static ssize_t fwu_sysfs_do_reflash_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- if (sscanf(buf, "%u", &input) != 1) {
- retval = -EINVAL;
- goto exit;
- }
-
- if (fwu->in_ub_mode) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: In microbootloader mode\n",
- __func__);
- retval = -EINVAL;
- goto exit;
- }
-
- if (!fwu->ext_data_source)
- return -EINVAL;
- else
- fwu->image = fwu->ext_data_source;
-
- if (input & LOCKDOWN) {
- fwu->do_lockdown = true;
- input &= ~LOCKDOWN;
- }
-
- if ((input != NORMAL) && (input != FORCE)) {
- retval = -EINVAL;
- goto exit;
- }
-
- if (input == FORCE)
- fwu->force_update = true;
-
- retval = synaptics_fw_updater(fwu->image);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to do reflash\n",
- __func__);
- goto exit;
- }
-
- retval = count;
-
-exit:
- kfree(fwu->ext_data_source);
- fwu->ext_data_source = NULL;
- fwu->image = NULL;
- fwu->force_update = FORCE_UPDATE;
- fwu->do_lockdown = DO_LOCKDOWN;
- return retval;
-}
-
-static ssize_t fwu_sysfs_write_config_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- if (sscanf(buf, "%u", &input) != 1) {
- retval = -EINVAL;
- goto exit;
- }
-
- if (input != 1) {
- retval = -EINVAL;
- goto exit;
- }
-
- if (fwu->in_ub_mode) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: In microbootloader mode\n",
- __func__);
- retval = -EINVAL;
- goto exit;
- }
-
- if (!fwu->ext_data_source)
- return -EINVAL;
- else
- fwu->image = fwu->ext_data_source;
-
- retval = fwu_start_write_config();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write config\n",
- __func__);
- goto exit;
- }
-
- retval = count;
-
-exit:
- kfree(fwu->ext_data_source);
- fwu->ext_data_source = NULL;
- fwu->image = NULL;
- return retval;
-}
-
-static ssize_t fwu_sysfs_read_config_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- if (input != 1)
- return -EINVAL;
-
- if (fwu->in_ub_mode) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: In microbootloader mode\n",
- __func__);
- return -EINVAL;
- }
-
- retval = fwu_do_read_config();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read config\n",
- __func__);
- return retval;
- }
-
- return count;
-}
-
-static ssize_t fwu_sysfs_config_area_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long config_area;
-
- retval = sstrtoul(buf, 10, &config_area);
- if (retval)
- return retval;
-
- fwu->config_area = config_area;
-
- return count;
-}
-
-static ssize_t fwu_sysfs_image_name_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- retval = secure_memcpy(fwu->image_name, MAX_IMAGE_NAME_LEN,
- buf, count, count);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy image file name\n",
- __func__);
- return retval;
- }
-
- return count;
-}
-
-static ssize_t fwu_sysfs_image_size_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long size;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- retval = sstrtoul(buf, 10, &size);
- if (retval)
- return retval;
-
- fwu->image_size = size;
- fwu->data_pos = 0;
-
- kfree(fwu->ext_data_source);
- fwu->ext_data_source = kzalloc(fwu->image_size, GFP_KERNEL);
- if (!fwu->ext_data_source) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for image data\n",
- __func__);
- return -ENOMEM;
- }
-
- return count;
-}
-
-static ssize_t fwu_sysfs_block_size_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", fwu->block_size);
-}
-
-static ssize_t fwu_sysfs_firmware_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.ui_firmware);
-}
-
-static ssize_t fwu_sysfs_configuration_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.ui_config);
-}
-
-static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.dp_config);
-}
-
-static ssize_t fwu_sysfs_perm_config_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.pm_config);
-}
-
-static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.bl_config);
-}
-
-static ssize_t fwu_sysfs_guest_code_block_count_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", fwu->blkcount.guest_code);
-}
-
-static ssize_t fwu_sysfs_write_guest_code_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
-
- if (sscanf(buf, "%u", &input) != 1) {
- retval = -EINVAL;
- goto exit;
- }
-
- if (input != 1) {
- retval = -EINVAL;
- goto exit;
- }
-
- if (fwu->in_ub_mode) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: In microbootloader mode\n",
- __func__);
- retval = -EINVAL;
- goto exit;
- }
-
- if (!fwu->ext_data_source)
- return -EINVAL;
- else
- fwu->image = fwu->ext_data_source;
-
- retval = fwu_start_write_guest_code();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write guest code\n",
- __func__);
- goto exit;
- }
-
- retval = count;
-
-exit:
- kfree(fwu->ext_data_source);
- fwu->ext_data_source = NULL;
- fwu->image = NULL;
- return retval;
-}
-
-static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
- unsigned char intr_mask)
-{
- if (!fwu)
- return;
-
- if (fwu->intr_mask & intr_mask)
- fwu_read_flash_status();
-
- return;
-}
-
-static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- unsigned char attr_count;
- struct pdt_properties pdt_props;
-
- if (fwu) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Handle already exists\n",
- __func__);
- return 0;
- }
-
- fwu = kzalloc(sizeof(*fwu), GFP_KERNEL);
- if (!fwu) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for fwu\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- fwu->image_name = kzalloc(MAX_IMAGE_NAME_LEN, GFP_KERNEL);
- if (!fwu->image_name) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for image name\n",
- __func__);
- retval = -ENOMEM;
- goto exit_free_fwu;
- }
-
- fwu->rmi4_data = rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- PDT_PROPS,
- pdt_props.data,
- sizeof(pdt_props.data));
- if (retval < 0) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Failed to read PDT properties, assuming 0x00\n",
- __func__);
- } else if (pdt_props.has_bsr) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Reflash for LTS not currently supported\n",
- __func__);
- retval = -ENODEV;
- goto exit_free_mem;
- }
-
- retval = fwu_scan_pdt();
- if (retval < 0)
- goto exit_free_mem;
-
- if (!fwu->in_ub_mode) {
- retval = fwu_read_f34_queries();
- if (retval < 0)
- goto exit_free_mem;
-
- retval = fwu_get_device_config_id();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read device config ID\n",
- __func__);
- goto exit_free_mem;
- }
- }
-
- fwu->force_update = FORCE_UPDATE;
- fwu->do_lockdown = DO_LOCKDOWN;
- fwu->initialized = true;
-
- retval = sysfs_create_bin_file(&rmi4_data->input_dev->dev.kobj,
- &dev_attr_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs bin file\n",
- __func__);
- goto exit_free_mem;
- }
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs attributes\n",
- __func__);
- retval = -ENODEV;
- goto exit_remove_attrs;
- }
- }
-
-#ifdef DO_STARTUP_FW_UPDATE
- fwu->fwu_workqueue = create_singlethread_workqueue("fwu_workqueue");
- INIT_WORK(&fwu->fwu_work, fwu_startup_fw_update_work);
- queue_work(fwu->fwu_workqueue,
- &fwu->fwu_work);
-#endif
-
- return 0;
-
-exit_remove_attrs:
- for (attr_count--; attr_count >= 0; attr_count--) {
- sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- }
-
- sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
-
-exit_free_mem:
- kfree(fwu->image_name);
-
-exit_free_fwu:
- kfree(fwu);
- fwu = NULL;
-
-exit:
- return retval;
-}
-
-static void synaptics_rmi4_fwu_remove(struct synaptics_rmi4_data *rmi4_data)
-{
- unsigned char attr_count;
-
- if (!fwu)
- goto exit;
-
-#ifdef DO_STARTUP_FW_UPDATE
- cancel_work_sync(&fwu->fwu_work);
- flush_workqueue(fwu->fwu_workqueue);
- destroy_workqueue(fwu->fwu_workqueue);
-#endif
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- }
-
- sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data);
-
- kfree(fwu->read_config_buf);
- kfree(fwu->image_name);
- kfree(fwu);
- fwu = NULL;
-
-exit:
- complete(&fwu_remove_complete);
-
- return;
-}
-
-static void synaptics_rmi4_fwu_reset(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
-
- if (!fwu) {
- synaptics_rmi4_fwu_init(rmi4_data);
- return;
- }
-
- retval = fwu_scan_pdt();
- if (retval < 0)
- return;
-
- if (!fwu->in_ub_mode)
- fwu_read_f34_queries();
-
- return;
-}
-
-static struct synaptics_rmi4_exp_fn fwu_module = {
- .fn_type = RMI_FW_UPDATER,
- .init = synaptics_rmi4_fwu_init,
- .remove = synaptics_rmi4_fwu_remove,
- .reset = synaptics_rmi4_fwu_reset,
- .reinit = NULL,
- .early_suspend = NULL,
- .suspend = NULL,
- .resume = NULL,
- .late_resume = NULL,
- .attn = synaptics_rmi4_fwu_attn,
-};
-
-static int __init rmi4_fw_update_module_init(void)
-{
- synaptics_rmi4_new_function(&fwu_module, true);
-
- return 0;
-}
-
-static void __exit rmi4_fw_update_module_exit(void)
-{
- synaptics_rmi4_new_function(&fwu_module, false);
-
- wait_for_completion(&fwu_remove_complete);
-
- return;
-}
-
-module_init(rmi4_fw_update_module_init);
-module_exit(rmi4_fw_update_module_exit);
-
-MODULE_AUTHOR("Synaptics, Inc.");
-MODULE_DESCRIPTION("Synaptics DSX FW Update Module");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c
deleted file mode 100644
index de8656389cad..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_gesture.c
+++ /dev/null
@@ -1,2308 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx_v2_6.h>
-#include "synaptics_dsx_core.h"
-
-#define GESTURE_PHYS_NAME "synaptics_dsx/gesture"
-
-#define TUNING_SYSFS_DIR_NAME "tuning"
-
-#define STORE_GESTURES
-#ifdef STORE_GESTURES
-#define GESTURES_TO_STORE 10
-#endif
-
-#define CTRL23_FINGER_REPORT_ENABLE_BIT 0
-#define CTRL27_UDG_ENABLE_BIT 4
-#define WAKEUP_GESTURE_MODE 0x02
-
-static ssize_t udg_sysfs_engine_enable_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t udg_sysfs_detection_enable_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t udg_sysfs_detection_score_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_detection_index_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_registration_enable_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t udg_sysfs_registration_begin_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t udg_sysfs_registration_status_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_template_size_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_template_max_index_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_template_detection_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_template_index_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t udg_sysfs_template_valid_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_template_valid_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t udg_sysfs_template_clear_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t udg_sysfs_trace_size_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_template_data_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
-
-static ssize_t udg_sysfs_template_data_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
-
-static ssize_t udg_sysfs_trace_data_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
-
-static ssize_t udg_sysfs_template_displacement_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_template_displacement_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t udg_sysfs_rotation_invariance_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_rotation_invariance_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t udg_sysfs_scale_invariance_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_scale_invariance_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t udg_sysfs_threshold_factor_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_threshold_factor_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t udg_sysfs_match_metric_threshold_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_match_metric_threshold_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t udg_sysfs_max_inter_stroke_time_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t udg_sysfs_max_inter_stroke_time_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static int udg_read_tuning_params(void);
-
-static int udg_write_tuning_params(void);
-
-static int udg_detection_enable(bool enable);
-
-static int udg_engine_enable(bool enable);
-
-static int udg_set_index(unsigned char index);
-
-#ifdef STORE_GESTURES
-static int udg_read_valid_data(void);
-static int udg_write_valid_data(void);
-static int udg_read_template_data(unsigned char index);
-static int udg_write_template_data(void);
-#endif
-
-enum gesture_type {
- DETECTION = 0x0f,
- REGISTRATION = 0x10,
-};
-
-struct udg_tuning {
- union {
- struct {
- unsigned char maximum_number_of_templates;
- unsigned char template_size;
- unsigned char template_disp_lsb;
- unsigned char template_disp_msb;
- unsigned char rotation_inv_lsb;
- unsigned char rotation_inv_msb;
- unsigned char scale_inv_lsb;
- unsigned char scale_inv_msb;
- unsigned char thres_factor_lsb;
- unsigned char thres_factor_msb;
- unsigned char metric_thres_lsb;
- unsigned char metric_thres_msb;
- unsigned char inter_stroke_lsb;
- unsigned char inter_stroke_msb;
- } __packed;
- unsigned char data[14];
- };
-};
-
-struct udg_addr {
- unsigned short data_4;
- unsigned short ctrl_18;
- unsigned short ctrl_20;
- unsigned short ctrl_23;
- unsigned short ctrl_27;
- unsigned short ctrl_41;
- unsigned short trace_x;
- unsigned short trace_y;
- unsigned short trace_segment;
- unsigned short template_helper;
- unsigned short template_data;
- unsigned short template_flags;
-};
-
-struct synaptics_rmi4_f12_query_0 {
- union {
- struct {
- struct {
- unsigned char has_register_descriptors:1;
- unsigned char has_closed_cover:1;
- unsigned char has_fast_glove_detect:1;
- unsigned char has_dribble:1;
- unsigned char has_4p4_jitter_filter_strength:1;
- unsigned char f12_query0_s0_b5__7:3;
- } __packed;
- struct {
- unsigned char max_num_templates:4;
- unsigned char f12_query0_s1_b4__7:4;
- unsigned char template_size_lsb;
- unsigned char template_size_msb;
- } __packed;
- };
- unsigned char data[4];
- };
-};
-
-struct synaptics_rmi4_f12_query_5 {
- union {
- struct {
- unsigned char size_of_query6;
- struct {
- unsigned char ctrl0_is_present:1;
- unsigned char ctrl1_is_present:1;
- unsigned char ctrl2_is_present:1;
- unsigned char ctrl3_is_present:1;
- unsigned char ctrl4_is_present:1;
- unsigned char ctrl5_is_present:1;
- unsigned char ctrl6_is_present:1;
- unsigned char ctrl7_is_present:1;
- } __packed;
- struct {
- unsigned char ctrl8_is_present:1;
- unsigned char ctrl9_is_present:1;
- unsigned char ctrl10_is_present:1;
- unsigned char ctrl11_is_present:1;
- unsigned char ctrl12_is_present:1;
- unsigned char ctrl13_is_present:1;
- unsigned char ctrl14_is_present:1;
- unsigned char ctrl15_is_present:1;
- } __packed;
- struct {
- unsigned char ctrl16_is_present:1;
- unsigned char ctrl17_is_present:1;
- unsigned char ctrl18_is_present:1;
- unsigned char ctrl19_is_present:1;
- unsigned char ctrl20_is_present:1;
- unsigned char ctrl21_is_present:1;
- unsigned char ctrl22_is_present:1;
- unsigned char ctrl23_is_present:1;
- } __packed;
- struct {
- unsigned char ctrl24_is_present:1;
- unsigned char ctrl25_is_present:1;
- unsigned char ctrl26_is_present:1;
- unsigned char ctrl27_is_present:1;
- unsigned char ctrl28_is_present:1;
- unsigned char ctrl29_is_present:1;
- unsigned char ctrl30_is_present:1;
- unsigned char ctrl31_is_present:1;
- } __packed;
- struct {
- unsigned char ctrl32_is_present:1;
- unsigned char ctrl33_is_present:1;
- unsigned char ctrl34_is_present:1;
- unsigned char ctrl35_is_present:1;
- unsigned char ctrl36_is_present:1;
- unsigned char ctrl37_is_present:1;
- unsigned char ctrl38_is_present:1;
- unsigned char ctrl39_is_present:1;
- } __packed;
- struct {
- unsigned char ctrl40_is_present:1;
- unsigned char ctrl41_is_present:1;
- unsigned char ctrl42_is_present:1;
- unsigned char ctrl43_is_present:1;
- unsigned char ctrl44_is_present:1;
- unsigned char ctrl45_is_present:1;
- unsigned char ctrl46_is_present:1;
- unsigned char ctrl47_is_present:1;
- } __packed;
- };
- unsigned char data[7];
- };
-};
-
-struct synaptics_rmi4_f12_query_8 {
- union {
- struct {
- unsigned char size_of_query9;
- struct {
- unsigned char data0_is_present:1;
- unsigned char data1_is_present:1;
- unsigned char data2_is_present:1;
- unsigned char data3_is_present:1;
- unsigned char data4_is_present:1;
- unsigned char data5_is_present:1;
- unsigned char data6_is_present:1;
- unsigned char data7_is_present:1;
- } __packed;
- struct {
- unsigned char data8_is_present:1;
- unsigned char data9_is_present:1;
- unsigned char data10_is_present:1;
- unsigned char data11_is_present:1;
- unsigned char data12_is_present:1;
- unsigned char data13_is_present:1;
- unsigned char data14_is_present:1;
- unsigned char data15_is_present:1;
- } __packed;
- struct {
- unsigned char data16_is_present:1;
- unsigned char data17_is_present:1;
- unsigned char data18_is_present:1;
- unsigned char data19_is_present:1;
- unsigned char data20_is_present:1;
- unsigned char data21_is_present:1;
- unsigned char data22_is_present:1;
- unsigned char data23_is_present:1;
- } __packed;
- };
- unsigned char data[4];
- };
-};
-
-struct synaptics_rmi4_f12_control_41 {
- union {
- struct {
- unsigned char enable_registration:1;
- unsigned char template_index:4;
- unsigned char begin:1;
- unsigned char f12_ctrl41_b6__7:2;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct synaptics_rmi4_udg_handle {
- atomic_t attn_event;
- unsigned char intr_mask;
- unsigned char report_flags;
- unsigned char object_type_enable1;
- unsigned char object_type_enable2;
- unsigned char trace_size;
- unsigned char template_index;
- unsigned char max_num_templates;
- unsigned char detection_score;
- unsigned char detection_index;
- unsigned char detection_status;
- unsigned char registration_status;
- unsigned char *ctrl_buf;
- unsigned char *trace_data_buf;
- unsigned char *template_data_buf;
-#ifdef STORE_GESTURES
- unsigned char gestures_to_store;
- unsigned char *storage_buf;
- unsigned char valid_buf[2];
-#endif
- unsigned short trace_data_buf_size;
- unsigned short template_size;
- unsigned short template_data_size;
- unsigned short query_base_addr;
- unsigned short control_base_addr;
- unsigned short data_base_addr;
- unsigned short command_base_addr;
- unsigned short ctrl_18_sub10_off;
- unsigned short ctrl_20_sub1_off;
- unsigned short ctrl_23_sub3_off;
- unsigned short ctrl_27_sub5_off;
- struct input_dev *udg_dev;
- struct kobject *tuning_dir;
- struct udg_addr addr;
- struct udg_tuning tuning;
- struct synaptics_rmi4_data *rmi4_data;
-};
-
-static struct device_attribute attrs[] = {
- __ATTR(engine_enable, S_IWUGO,
- NULL,
- udg_sysfs_engine_enable_store),
- __ATTR(detection_enable, S_IWUGO,
- NULL,
- udg_sysfs_detection_enable_store),
- __ATTR(detection_score, S_IRUGO,
- udg_sysfs_detection_score_show,
- NULL),
- __ATTR(detection_index, S_IRUGO,
- udg_sysfs_detection_index_show,
- NULL),
- __ATTR(registration_enable, S_IWUGO,
- NULL,
- udg_sysfs_registration_enable_store),
- __ATTR(registration_begin, S_IWUGO,
- NULL,
- udg_sysfs_registration_begin_store),
- __ATTR(registration_status, S_IRUGO,
- udg_sysfs_registration_status_show,
- NULL),
- __ATTR(template_size, S_IRUGO,
- udg_sysfs_template_size_show,
- NULL),
- __ATTR(template_max_index, S_IRUGO,
- udg_sysfs_template_max_index_show,
- NULL),
- __ATTR(template_detection, S_IRUGO,
- udg_sysfs_template_detection_show,
- NULL),
- __ATTR(template_index, S_IWUGO,
- NULL,
- udg_sysfs_template_index_store),
- __ATTR(template_valid, (S_IRUGO | S_IWUGO),
- udg_sysfs_template_valid_show,
- udg_sysfs_template_valid_store),
- __ATTR(template_clear, S_IWUGO,
- NULL,
- udg_sysfs_template_clear_store),
- __ATTR(trace_size, S_IRUGO,
- udg_sysfs_trace_size_show,
- NULL),
-};
-
-static struct bin_attribute template_data = {
- .attr = {
- .name = "template_data",
- .mode = (S_IRUGO | S_IWUGO),
- },
- .size = 0,
- .read = udg_sysfs_template_data_show,
- .write = udg_sysfs_template_data_store,
-};
-
-static struct bin_attribute trace_data = {
- .attr = {
- .name = "trace_data",
- .mode = S_IRUGO,
- },
- .size = 0,
- .read = udg_sysfs_trace_data_show,
- .write = NULL,
-};
-
-static struct device_attribute params[] = {
- __ATTR(template_displacement, (S_IRUGO | S_IWUGO),
- udg_sysfs_template_displacement_show,
- udg_sysfs_template_displacement_store),
- __ATTR(rotation_invariance, (S_IRUGO | S_IWUGO),
- udg_sysfs_rotation_invariance_show,
- udg_sysfs_rotation_invariance_store),
- __ATTR(scale_invariance, (S_IRUGO | S_IWUGO),
- udg_sysfs_scale_invariance_show,
- udg_sysfs_scale_invariance_store),
- __ATTR(threshold_factor, (S_IRUGO | S_IWUGO),
- udg_sysfs_threshold_factor_show,
- udg_sysfs_threshold_factor_store),
- __ATTR(match_metric_threshold, (S_IRUGO | S_IWUGO),
- udg_sysfs_match_metric_threshold_show,
- udg_sysfs_match_metric_threshold_store),
- __ATTR(max_inter_stroke_time, (S_IRUGO | S_IWUGO),
- udg_sysfs_max_inter_stroke_time_show,
- udg_sysfs_max_inter_stroke_time_store),
-};
-
-static struct synaptics_rmi4_udg_handle *udg;
-
-static unsigned char ctrl_18_sub_size[] = {10, 10, 10, 2, 3, 4, 3, 3, 1, 1};
-static unsigned char ctrl_20_sub_size[] = {2};
-static unsigned char ctrl_23_sub_size[] = {1, 1, 1};
-static unsigned char ctrl_27_sub_size[] = {1, 5, 2, 1, 7};
-
-DECLARE_COMPLETION(udg_remove_complete);
-
-static ssize_t udg_sysfs_engine_enable_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- bool enable;
- unsigned int input;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- if (input == 1)
- enable = true;
- else if (input == 0)
- enable = false;
- else
- return -EINVAL;
-
- retval = udg_engine_enable(enable);
- if (retval < 0)
- return retval;
-
- return count;
-}
-
-static ssize_t udg_sysfs_detection_enable_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- bool enable;
- unsigned int input;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- if (input == 1)
- enable = true;
- else if (input == 0)
- enable = false;
- else
- return -EINVAL;
-
- udg->detection_status = 0;
-
- retval = udg_detection_enable(enable);
- if (retval < 0)
- return retval;
-
- return count;
-}
-
-static ssize_t udg_sysfs_detection_score_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", udg->detection_score);
-}
-
-static ssize_t udg_sysfs_detection_index_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", udg->detection_index);
-}
-
-static ssize_t udg_sysfs_registration_enable_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- bool enable;
- unsigned int input;
- struct synaptics_rmi4_f12_control_41 control_41;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- if (input == 1)
- enable = true;
- else if (input == 0)
- enable = false;
- else
- return -EINVAL;
-
- if (enable) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.ctrl_23,
- udg->ctrl_buf,
- udg->ctrl_23_sub3_off + 1);
- if (retval < 0)
- return retval;
-
- udg->ctrl_buf[0] = 0;
- udg->ctrl_buf[0] |= (1 << CTRL23_FINGER_REPORT_ENABLE_BIT);
- if (udg->ctrl_23_sub3_off)
- udg->ctrl_buf[udg->ctrl_23_sub3_off] = 0;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.ctrl_23,
- udg->ctrl_buf,
- udg->ctrl_23_sub3_off + 1);
- if (retval < 0)
- return retval;
- } else {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.ctrl_23,
- udg->ctrl_buf,
- udg->ctrl_23_sub3_off + 1);
- if (retval < 0)
- return retval;
-
- udg->ctrl_buf[0] = udg->object_type_enable1;
- if (udg->ctrl_23_sub3_off) {
- udg->ctrl_buf[udg->ctrl_23_sub3_off] =
- udg->object_type_enable2;
- }
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.ctrl_23,
- udg->ctrl_buf,
- udg->ctrl_23_sub3_off + 1);
- if (retval < 0)
- return retval;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.ctrl_41,
- control_41.data,
- sizeof(control_41.data));
- if (retval < 0)
- return retval;
-
- control_41.enable_registration = enable ? 1 : 0;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.ctrl_41,
- control_41.data,
- sizeof(control_41.data));
- if (retval < 0)
- return retval;
-
- return count;
-}
-
-static ssize_t udg_sysfs_registration_begin_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- bool begin;
- unsigned int input;
- struct synaptics_rmi4_f12_control_41 control_41;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- if (input == 1)
- begin = true;
- else if (input == 0)
- begin = false;
- else
- return -EINVAL;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.ctrl_41,
- control_41.data,
- sizeof(control_41.data));
- if (retval < 0)
- return retval;
-
- control_41.begin = begin ? 1 : 0;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.ctrl_41,
- control_41.data,
- sizeof(control_41.data));
- if (retval < 0)
- return retval;
-
- return count;
-}
-
-static ssize_t udg_sysfs_registration_status_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "0x%02x\n", udg->registration_status);
-}
-
-static ssize_t udg_sysfs_template_size_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", udg->template_size);
-}
-
-static ssize_t udg_sysfs_template_max_index_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", udg->max_num_templates - 1);
-}
-
-static ssize_t udg_sysfs_template_detection_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int retval;
- int attn_event;
- unsigned char detection_status;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- attn_event = atomic_read(&udg->attn_event);
- atomic_set(&udg->attn_event, 0);
-
- if (attn_event == 0)
- return snprintf(buf, PAGE_SIZE, "0\n");
-
- if (udg->detection_status == 0) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.data_4,
- rmi4_data->gesture_detection,
- sizeof(rmi4_data->gesture_detection));
- if (retval < 0)
- return retval;
-
- udg->detection_status = rmi4_data->gesture_detection[0];
- }
-
- detection_status = udg->detection_status;
- udg->detection_status = 0;
-
- switch (detection_status) {
- case DETECTION:
- udg->detection_score = rmi4_data->gesture_detection[1];
- udg->detection_index = rmi4_data->gesture_detection[4];
- udg->trace_size = rmi4_data->gesture_detection[3];
- break;
- case REGISTRATION:
- udg->registration_status = rmi4_data->gesture_detection[1];
- udg->trace_size = rmi4_data->gesture_detection[3];
- break;
- default:
- return snprintf(buf, PAGE_SIZE, "0\n");
- }
-
- return snprintf(buf, PAGE_SIZE, "0x%02x\n", detection_status);
-}
-
-static ssize_t udg_sysfs_template_index_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long index;
-
- retval = sstrtoul(buf, 10, &index);
- if (retval)
- return retval;
-
- retval = udg_set_index((unsigned char)index);
- if (retval < 0)
- return retval;
-
- return count;
-}
-
-static ssize_t udg_sysfs_template_valid_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int retval;
- unsigned char valid;
- unsigned char offset;
- unsigned char byte_num;
- unsigned char template_flags[2];
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- byte_num = udg->template_index / 8;
- offset = udg->template_index % 8;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.template_flags,
- template_flags,
- sizeof(template_flags));
- if (retval < 0)
- return retval;
-
- valid = (template_flags[byte_num] & (1 << offset)) >> offset;
-
- return snprintf(buf, PAGE_SIZE, "%u\n", valid);
-}
-
-static ssize_t udg_sysfs_template_valid_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long valid;
- unsigned char offset;
- unsigned char byte_num;
- unsigned char template_flags[2];
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- retval = sstrtoul(buf, 10, &valid);
- if (retval)
- return retval;
-
- if (valid > 0)
- valid = 1;
-
- byte_num = udg->template_index / 8;
- offset = udg->template_index % 8;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.template_flags,
- template_flags,
- sizeof(template_flags));
- if (retval < 0)
- return retval;
-
- if (valid)
- template_flags[byte_num] |= (1 << offset);
- else
- template_flags[byte_num] &= ~(1 << offset);
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.template_flags,
- template_flags,
- sizeof(template_flags));
- if (retval < 0)
- return retval;
-
-#ifdef STORE_GESTURES
- udg_read_valid_data();
-#endif
-
- return count;
-}
-
-static ssize_t udg_sysfs_template_clear_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned int input;
- const char cmd[] = {'0', 0};
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- if (input != 1)
- return -EINVAL;
-
- memset(udg->template_data_buf, 0x00, udg->template_data_size);
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.template_data,
- udg->template_data_buf,
- udg->template_data_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to clear template data\n",
- __func__);
- return retval;
- }
-
- retval = udg_sysfs_template_valid_store(dev, attr, cmd, 1);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to clear valid bit\n",
- __func__);
- return retval;
- }
-
-#ifdef STORE_GESTURES
- udg_read_template_data(udg->template_index);
- udg_read_valid_data();
-#endif
-
- return count;
-}
-
-static ssize_t udg_sysfs_trace_size_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", udg->trace_size);
-}
-
-static ssize_t udg_sysfs_trace_data_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
-{
- int retval;
- unsigned short index = 0;
- unsigned short trace_data_size;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- trace_data_size = udg->trace_size * 5;
-
- if (trace_data_size == 0)
- return -EINVAL;
-
- if (count < trace_data_size) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Not enough space (%d bytes) in buffer\n",
- __func__, (unsigned int)count);
- return -EINVAL;
- }
-
- if (udg->trace_data_buf_size < trace_data_size) {
- if (udg->trace_data_buf_size)
- kfree(udg->trace_data_buf);
- udg->trace_data_buf = kzalloc(trace_data_size, GFP_KERNEL);
- if (!udg->trace_data_buf) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for trace data buffer\n",
- __func__);
- udg->trace_data_buf_size = 0;
- return -ENOMEM;
- }
- udg->trace_data_buf_size = trace_data_size;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.trace_x,
- &udg->trace_data_buf[index],
- udg->trace_size * 2);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read trace X data\n",
- __func__);
- return retval;
- } else {
- index += udg->trace_size * 2;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.trace_y,
- &udg->trace_data_buf[index],
- udg->trace_size * 2);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read trace Y data\n",
- __func__);
- return retval;
- } else {
- index += udg->trace_size * 2;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.trace_segment,
- &udg->trace_data_buf[index],
- udg->trace_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read trace segment data\n",
- __func__);
- return retval;
- }
-
- retval = secure_memcpy(buf, count, udg->trace_data_buf,
- udg->trace_data_buf_size, trace_data_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy trace data\n",
- __func__);
- return retval;
- }
-
- return trace_data_size;
-}
-
-static ssize_t udg_sysfs_template_data_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- if (count < udg->template_data_size) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Not enough space (%d bytes) in buffer\n",
- __func__, (unsigned int)count);
- return -EINVAL;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.template_data,
- udg->template_data_buf,
- udg->template_data_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read template data\n",
- __func__);
- return retval;
- }
-
- retval = secure_memcpy(buf, count, udg->template_data_buf,
- udg->template_data_size, udg->template_data_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy template data\n",
- __func__);
- return retval;
- }
-
-#ifdef STORE_GESTURES
- udg_read_template_data(udg->template_index);
- udg_read_valid_data();
-#endif
-
- return udg->template_data_size;
-}
-
-static ssize_t udg_sysfs_template_data_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- retval = secure_memcpy(udg->template_data_buf, udg->template_data_size,
- buf, count, count);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy template data\n",
- __func__);
- return retval;
- }
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.template_data,
- udg->template_data_buf,
- count);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write template data\n",
- __func__);
- return retval;
- }
-
-#ifdef STORE_GESTURES
- udg_read_template_data(udg->template_index);
- udg_read_valid_data();
-#endif
-
- return count;
-}
-
-static ssize_t udg_sysfs_template_displacement_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int retval;
- unsigned short template_displacement;
-
- retval = udg_read_tuning_params();
- if (retval < 0)
- return retval;
-
- template_displacement =
- ((unsigned short)udg->tuning.template_disp_lsb << 0) |
- ((unsigned short)udg->tuning.template_disp_msb << 8);
-
- return snprintf(buf, PAGE_SIZE, "%u\n", template_displacement);
-}
-
-static ssize_t udg_sysfs_template_displacement_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long input;
-
- retval = sstrtoul(buf, 10, &input);
- if (retval)
- return retval;
-
- retval = udg_read_tuning_params();
- if (retval < 0)
- return retval;
-
- udg->tuning.template_disp_lsb = (unsigned char)(input >> 0);
- udg->tuning.template_disp_msb = (unsigned char)(input >> 8);
-
- retval = udg_write_tuning_params();
- if (retval < 0)
- return retval;
-
- return count;
-}
-
-static ssize_t udg_sysfs_rotation_invariance_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int retval;
- unsigned short rotation_invariance;
-
- retval = udg_read_tuning_params();
- if (retval < 0)
- return retval;
-
- rotation_invariance =
- ((unsigned short)udg->tuning.rotation_inv_lsb << 0) |
- ((unsigned short)udg->tuning.rotation_inv_msb << 8);
-
- return snprintf(buf, PAGE_SIZE, "%u\n", rotation_invariance);
-}
-
-static ssize_t udg_sysfs_rotation_invariance_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long input;
-
- retval = sstrtoul(buf, 10, &input);
- if (retval)
- return retval;
-
- retval = udg_read_tuning_params();
- if (retval < 0)
- return retval;
-
- udg->tuning.rotation_inv_lsb = (unsigned char)(input >> 0);
- udg->tuning.rotation_inv_msb = (unsigned char)(input >> 8);
-
- retval = udg_write_tuning_params();
- if (retval < 0)
- return retval;
-
- return count;
-}
-
-static ssize_t udg_sysfs_scale_invariance_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int retval;
- unsigned short scale_invariance;
-
- retval = udg_read_tuning_params();
- if (retval < 0)
- return retval;
-
- scale_invariance =
- ((unsigned short)udg->tuning.scale_inv_lsb << 0) |
- ((unsigned short)udg->tuning.scale_inv_msb << 8);
-
- return snprintf(buf, PAGE_SIZE, "%u\n", scale_invariance);
-}
-
-static ssize_t udg_sysfs_scale_invariance_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long input;
-
- retval = sstrtoul(buf, 10, &input);
- if (retval)
- return retval;
-
- retval = udg_read_tuning_params();
- if (retval < 0)
- return retval;
-
- udg->tuning.scale_inv_lsb = (unsigned char)(input >> 0);
- udg->tuning.scale_inv_msb = (unsigned char)(input >> 8);
-
- retval = udg_write_tuning_params();
- if (retval < 0)
- return retval;
-
- return count;
-}
-
-static ssize_t udg_sysfs_threshold_factor_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int retval;
- unsigned short threshold_factor;
-
- retval = udg_read_tuning_params();
- if (retval < 0)
- return retval;
-
- threshold_factor =
- ((unsigned short)udg->tuning.thres_factor_lsb << 0) |
- ((unsigned short)udg->tuning.thres_factor_msb << 8);
-
- return snprintf(buf, PAGE_SIZE, "%u\n", threshold_factor);
-}
-
-static ssize_t udg_sysfs_threshold_factor_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long input;
-
- retval = sstrtoul(buf, 10, &input);
- if (retval)
- return retval;
-
- retval = udg_read_tuning_params();
- if (retval < 0)
- return retval;
-
- udg->tuning.thres_factor_lsb = (unsigned char)(input >> 0);
- udg->tuning.thres_factor_msb = (unsigned char)(input >> 8);
-
- retval = udg_write_tuning_params();
- if (retval < 0)
- return retval;
-
- return count;
-}
-
-static ssize_t udg_sysfs_match_metric_threshold_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int retval;
- unsigned short match_metric_threshold;
-
- retval = udg_read_tuning_params();
- if (retval < 0)
- return retval;
-
- match_metric_threshold =
- ((unsigned short)udg->tuning.metric_thres_lsb << 0) |
- ((unsigned short)udg->tuning.metric_thres_msb << 8);
-
- return snprintf(buf, PAGE_SIZE, "%u\n", match_metric_threshold);
-}
-
-static ssize_t udg_sysfs_match_metric_threshold_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long input;
-
- retval = sstrtoul(buf, 10, &input);
- if (retval)
- return retval;
-
- retval = udg_read_tuning_params();
- if (retval < 0)
- return retval;
-
- udg->tuning.metric_thres_lsb = (unsigned char)(input >> 0);
- udg->tuning.metric_thres_msb = (unsigned char)(input >> 8);
-
- retval = udg_write_tuning_params();
- if (retval < 0)
- return retval;
-
- return count;
-}
-
-static ssize_t udg_sysfs_max_inter_stroke_time_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int retval;
- unsigned short max_inter_stroke_time;
-
- retval = udg_read_tuning_params();
- if (retval < 0)
- return retval;
-
- max_inter_stroke_time =
- ((unsigned short)udg->tuning.inter_stroke_lsb << 0) |
- ((unsigned short)udg->tuning.inter_stroke_msb << 8);
-
- return snprintf(buf, PAGE_SIZE, "%u\n", max_inter_stroke_time);
-}
-
-static ssize_t udg_sysfs_max_inter_stroke_time_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long input;
-
- retval = sstrtoul(buf, 10, &input);
- if (retval)
- return retval;
-
- retval = udg_read_tuning_params();
- if (retval < 0)
- return retval;
-
- udg->tuning.inter_stroke_lsb = (unsigned char)(input >> 0);
- udg->tuning.inter_stroke_msb = (unsigned char)(input >> 8);
-
- retval = udg_write_tuning_params();
- if (retval < 0)
- return retval;
-
- return count;
-}
-
-static int udg_ctrl_subpacket(unsigned char ctrlreg,
- unsigned char subpacket,
- struct synaptics_rmi4_f12_query_5 *query_5)
-{
- int retval;
- unsigned char cnt;
- unsigned char regnum;
- unsigned char bitnum;
- unsigned char q5_index;
- unsigned char q6_index;
- unsigned char offset;
- unsigned char max_ctrlreg;
- unsigned char *query_6;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- max_ctrlreg = (sizeof(query_5->data) - 1) * 8 - 1;
-
- if (ctrlreg > max_ctrlreg) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Control register number (%d) over limit\n",
- __func__, ctrlreg);
- return -EINVAL;
- }
-
- q5_index = ctrlreg / 8 + 1;
- bitnum = ctrlreg % 8;
- if ((query_5->data[q5_index] & (1 << bitnum)) == 0x00) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Control %d is not present\n",
- __func__, ctrlreg);
- return -EINVAL;
- }
-
- query_6 = kmalloc(query_5->size_of_query6, GFP_KERNEL);
- if (!query_6) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for query 6\n",
- __func__);
- return -ENOMEM;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->query_base_addr + 6,
- query_6,
- query_5->size_of_query6);
- if (retval < 0)
- goto exit;
-
- q6_index = 0;
-
- for (regnum = 0; regnum < ctrlreg; regnum++) {
- q5_index = regnum / 8 + 1;
- bitnum = regnum % 8;
- if ((query_5->data[q5_index] & (1 << bitnum)) == 0x00)
- continue;
-
- if (query_6[q6_index] == 0x00)
- q6_index += 3;
- else
- q6_index++;
-
- while (query_6[q6_index] & ~MASK_7BIT)
- q6_index++;
-
- q6_index++;
- }
-
- cnt = 0;
- q6_index++;
- offset = subpacket / 7;
- bitnum = subpacket % 7;
-
- do {
- if (cnt == offset) {
- if (query_6[q6_index + cnt] & (1 << bitnum))
- retval = 1;
- else
- retval = 0;
- goto exit;
- }
- cnt++;
- } while (query_6[q6_index + cnt - 1] & ~MASK_7BIT);
-
- retval = 0;
-
-exit:
- kfree(query_6);
-
- return retval;
-}
-
-static int udg_read_tuning_params(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.ctrl_18,
- udg->ctrl_buf,
- udg->ctrl_18_sub10_off + sizeof(struct udg_tuning));
- if (retval < 0)
- return retval;
-
- secure_memcpy(udg->tuning.data,
- sizeof(udg->tuning.data),
- (unsigned char *)&udg->ctrl_buf[udg->ctrl_18_sub10_off],
- sizeof(struct udg_tuning),
- sizeof(struct udg_tuning));
-
- return 0;
-}
-
-static int udg_write_tuning_params(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- secure_memcpy((unsigned char *)&udg->ctrl_buf[udg->ctrl_18_sub10_off],
- sizeof(struct udg_tuning),
- udg->tuning.data,
- sizeof(udg->tuning.data),
- sizeof(struct udg_tuning));
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.ctrl_18,
- udg->ctrl_buf,
- udg->ctrl_18_sub10_off + sizeof(struct udg_tuning));
- if (retval < 0)
- return retval;
-
- return 0;
-}
-
-static int udg_detection_enable(bool enable)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.ctrl_20,
- udg->ctrl_buf,
- udg->ctrl_20_sub1_off + 1);
- if (retval < 0)
- return retval;
-
- if (enable)
- udg->ctrl_buf[udg->ctrl_20_sub1_off] = WAKEUP_GESTURE_MODE;
- else
- udg->ctrl_buf[udg->ctrl_20_sub1_off] = udg->report_flags;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.ctrl_20,
- udg->ctrl_buf,
- udg->ctrl_20_sub1_off + 1);
- if (retval < 0)
- return retval;
-
- return 0;
-}
-
-static int udg_engine_enable(bool enable)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- if (enable) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.ctrl_27,
- udg->ctrl_buf,
- udg->ctrl_27_sub5_off + 1);
- if (retval < 0)
- return retval;
-
- udg->ctrl_buf[udg->ctrl_27_sub5_off] |=
- (1 << CTRL27_UDG_ENABLE_BIT);
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.ctrl_27,
- udg->ctrl_buf,
- udg->ctrl_27_sub5_off + 1);
- if (retval < 0)
- return retval;
- } else {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.ctrl_27,
- udg->ctrl_buf,
- udg->ctrl_27_sub5_off + 1);
- if (retval < 0)
- return retval;
-
- udg->ctrl_buf[udg->ctrl_27_sub5_off] &=
- ~(1 << CTRL27_UDG_ENABLE_BIT);
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.ctrl_27,
- udg->ctrl_buf,
- udg->ctrl_27_sub5_off + 1);
- if (retval < 0)
- return retval;
- }
-
- return 0;
-}
-
-static void udg_report(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- atomic_set(&udg->attn_event, 1);
-
- if (rmi4_data->suspend) {
- if (rmi4_data->gesture_detection[0] == 0) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.data_4,
- rmi4_data->gesture_detection,
- sizeof(rmi4_data->gesture_detection));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read gesture detection\n",
- __func__);
- return;
- }
- }
-
- udg->detection_status = rmi4_data->gesture_detection[0];
- rmi4_data->gesture_detection[0] = 0;
-
- if (udg->detection_status == DETECTION) {
- input_report_key(udg->udg_dev, KEY_WAKEUP, 1);
- input_sync(udg->udg_dev);
- input_report_key(udg->udg_dev, KEY_WAKEUP, 0);
- input_sync(udg->udg_dev);
- rmi4_data->suspend = false;
- }
- }
-
- return;
-}
-
-static int udg_set_index(unsigned char index)
-{
- int retval;
- struct synaptics_rmi4_f12_control_41 control_41;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- if (index >= udg->max_num_templates)
- return -EINVAL;
-
- udg->template_index = index;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.ctrl_41,
- control_41.data,
- sizeof(control_41.data));
- if (retval < 0)
- return retval;
-
- control_41.template_index = udg->template_index;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.ctrl_41,
- control_41.data,
- sizeof(control_41.data));
- if (retval < 0)
- return retval;
-
- return 0;
-}
-
-#ifdef STORE_GESTURES
-static int udg_read_valid_data(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.template_flags,
- udg->valid_buf,
- sizeof(udg->valid_buf));
- if (retval < 0)
- return retval;
-
- return 0;
-}
-
-static int udg_write_valid_data(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.template_flags,
- udg->valid_buf,
- sizeof(udg->valid_buf));
- if (retval < 0)
- return retval;
-
- return 0;
-}
-
-static int udg_read_template_data(unsigned char index)
-{
- int retval;
- unsigned char *storage;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- udg_set_index(index);
- storage = &(udg->storage_buf[index * udg->template_data_size]);
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.template_data,
- storage,
- udg->template_data_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read template data\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static int udg_write_template_data(void)
-{
- int retval;
- unsigned char ii;
- unsigned char *storage;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- for (ii = 0; ii < udg->gestures_to_store; ii++) {
- udg_set_index(ii);
- storage = &(udg->storage_buf[ii * udg->template_data_size]);
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- udg->addr.template_data,
- storage,
- udg->template_data_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write template data\n",
- __func__);
- return retval;
- }
- }
-
- return 0;
-}
-#endif
-
-static int udg_reg_init(void)
-{
- int retval;
- unsigned char ii;
- unsigned char data_offset;
- unsigned char size_of_query;
- unsigned char ctrl_18_offset;
- unsigned char ctrl_20_offset;
- unsigned char ctrl_23_offset;
- unsigned char ctrl_27_offset;
- unsigned char ctrl_41_offset;
- struct synaptics_rmi4_f12_query_0 query_0;
- struct synaptics_rmi4_f12_query_5 query_5;
- struct synaptics_rmi4_f12_query_8 query_8;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->query_base_addr + 7,
- &size_of_query,
- sizeof(size_of_query));
- if (retval < 0)
- return retval;
-
- if (size_of_query < 4) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: User defined gesture support unavailable (missing data registers)\n",
- __func__);
- retval = -ENODEV;
- return retval;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->query_base_addr + 8,
- query_8.data,
- sizeof(query_8.data));
- if (retval < 0)
- return retval;
-
- if ((query_8.data16_is_present) &&
- (query_8.data17_is_present) &&
- (query_8.data18_is_present) &&
- (query_8.data19_is_present) &&
- (query_8.data20_is_present) &&
- (query_8.data21_is_present)) {
- data_offset = query_8.data0_is_present +
- query_8.data1_is_present +
- query_8.data2_is_present +
- query_8.data3_is_present;
- udg->addr.data_4 = udg->data_base_addr + data_offset;
- data_offset = data_offset +
- query_8.data4_is_present +
- query_8.data5_is_present +
- query_8.data6_is_present +
- query_8.data7_is_present +
- query_8.data8_is_present +
- query_8.data9_is_present +
- query_8.data10_is_present +
- query_8.data11_is_present +
- query_8.data12_is_present +
- query_8.data13_is_present +
- query_8.data14_is_present +
- query_8.data15_is_present;
- udg->addr.trace_x = udg->data_base_addr + data_offset;
- udg->addr.trace_y = udg->addr.trace_x + 1;
- udg->addr.trace_segment = udg->addr.trace_y + 1;
- udg->addr.template_helper = udg->addr.trace_segment + 1;
- udg->addr.template_data = udg->addr.template_helper + 1;
- udg->addr.template_flags = udg->addr.template_data + 1;
- } else {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: User defined gesture support unavailable (missing data registers)\n",
- __func__);
- retval = -ENODEV;
- return retval;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->query_base_addr + 4,
- &size_of_query,
- sizeof(size_of_query));
- if (retval < 0)
- return retval;
-
- if (size_of_query < 7) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: User defined gesture support unavailable (missing control registers)\n",
- __func__);
- retval = -ENODEV;
- return retval;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->query_base_addr + 5,
- query_5.data,
- sizeof(query_5.data));
- if (retval < 0)
- return retval;
-
- ctrl_18_offset = query_5.ctrl0_is_present +
- query_5.ctrl1_is_present +
- query_5.ctrl2_is_present +
- query_5.ctrl3_is_present +
- query_5.ctrl4_is_present +
- query_5.ctrl5_is_present +
- query_5.ctrl6_is_present +
- query_5.ctrl7_is_present +
- query_5.ctrl8_is_present +
- query_5.ctrl9_is_present +
- query_5.ctrl10_is_present +
- query_5.ctrl11_is_present +
- query_5.ctrl12_is_present +
- query_5.ctrl13_is_present +
- query_5.ctrl14_is_present +
- query_5.ctrl15_is_present +
- query_5.ctrl16_is_present +
- query_5.ctrl17_is_present;
-
- ctrl_20_offset = ctrl_18_offset +
- query_5.ctrl18_is_present +
- query_5.ctrl19_is_present;
-
- ctrl_23_offset = ctrl_20_offset +
- query_5.ctrl20_is_present +
- query_5.ctrl21_is_present +
- query_5.ctrl22_is_present;
-
- ctrl_27_offset = ctrl_23_offset+
- query_5.ctrl23_is_present +
- query_5.ctrl24_is_present +
- query_5.ctrl25_is_present +
- query_5.ctrl26_is_present;
-
- ctrl_41_offset = ctrl_27_offset+
- query_5.ctrl27_is_present +
- query_5.ctrl28_is_present +
- query_5.ctrl29_is_present +
- query_5.ctrl30_is_present +
- query_5.ctrl31_is_present +
- query_5.ctrl32_is_present +
- query_5.ctrl33_is_present +
- query_5.ctrl34_is_present +
- query_5.ctrl35_is_present +
- query_5.ctrl36_is_present +
- query_5.ctrl37_is_present +
- query_5.ctrl38_is_present +
- query_5.ctrl39_is_present +
- query_5.ctrl40_is_present;
-
- udg->addr.ctrl_18 = udg->control_base_addr + ctrl_18_offset;
- udg->addr.ctrl_20 = udg->control_base_addr + ctrl_20_offset;
- udg->addr.ctrl_23 = udg->control_base_addr + ctrl_23_offset;
- udg->addr.ctrl_27 = udg->control_base_addr + ctrl_27_offset;
- udg->addr.ctrl_41 = udg->control_base_addr + ctrl_41_offset;
-
- udg->ctrl_18_sub10_off = 0;
- for (ii = 0; ii < 10; ii++) {
- retval = udg_ctrl_subpacket(18, ii, &query_5);
- if (retval == 1)
- udg->ctrl_18_sub10_off += ctrl_18_sub_size[ii];
- else if (retval < 0)
- return retval;
- }
-
- udg->ctrl_20_sub1_off = 0;
- for (ii = 0; ii < 1; ii++) {
- retval = udg_ctrl_subpacket(20, ii, &query_5);
- if (retval == 1)
- udg->ctrl_20_sub1_off += ctrl_20_sub_size[ii];
- else if (retval < 0)
- return retval;
- }
-
- udg->ctrl_23_sub3_off = 0;
- for (ii = 0; ii < 3; ii++) {
- retval = udg_ctrl_subpacket(23, ii, &query_5);
- if (retval == 1)
- udg->ctrl_23_sub3_off += ctrl_23_sub_size[ii];
- else if (retval < 0)
- return retval;
- }
-
- retval = udg_ctrl_subpacket(23, 3, &query_5);
- if (retval == 0)
- udg->ctrl_23_sub3_off = 0;
- else if (retval < 0)
- return retval;
-
- udg->ctrl_27_sub5_off = 0;
- for (ii = 0; ii < 5; ii++) {
- retval = udg_ctrl_subpacket(27, ii, &query_5);
- if (retval == 1)
- udg->ctrl_27_sub5_off += ctrl_27_sub_size[ii];
- else if (retval < 0)
- return retval;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->query_base_addr + 0,
- query_0.data,
- sizeof(query_0.data));
- if (retval < 0)
- return retval;
-
- udg->max_num_templates = query_0.max_num_templates;
- udg->template_size =
- ((unsigned short)query_0.template_size_lsb << 0) |
- ((unsigned short)query_0.template_size_msb << 8);
- udg->template_data_size = udg->template_size * 4 * 2 + 4 + 1;
-
-#ifdef STORE_GESTURES
- udg->gestures_to_store = udg->max_num_templates;
- if (GESTURES_TO_STORE < udg->gestures_to_store)
- udg->gestures_to_store = GESTURES_TO_STORE;
-#endif
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.ctrl_20,
- udg->ctrl_buf,
- udg->ctrl_20_sub1_off + 1);
- if (retval < 0)
- return retval;
-
- udg->report_flags = udg->ctrl_buf[udg->ctrl_20_sub1_off];
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- udg->addr.ctrl_23,
- udg->ctrl_buf,
- udg->ctrl_23_sub3_off + 1);
- if (retval < 0)
- return retval;
-
- udg->object_type_enable1 = udg->ctrl_buf[0];
- if (udg->ctrl_23_sub3_off)
- udg->object_type_enable2 = udg->ctrl_buf[udg->ctrl_23_sub3_off];
-
- return retval;
-}
-
-static int udg_scan_pdt(void)
-{
- int retval;
- unsigned char ii;
- unsigned char page;
- unsigned char intr_count = 0;
- unsigned char intr_off;
- unsigned char intr_src;
- unsigned short addr;
- struct synaptics_rmi4_fn_desc fd;
- struct synaptics_rmi4_data *rmi4_data = udg->rmi4_data;
-
- for (page = 0; page < PAGES_TO_SERVICE; page++) {
- for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
- addr |= (page << 8);
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- addr,
- (unsigned char *)&fd,
- sizeof(fd));
- if (retval < 0)
- return retval;
-
- addr &= ~(MASK_8BIT << 8);
-
- if (fd.fn_number) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Found F%02x\n",
- __func__, fd.fn_number);
- switch (fd.fn_number) {
- case SYNAPTICS_RMI4_F12:
- goto f12_found;
- break;
- }
- } else {
- break;
- }
-
- intr_count += fd.intr_src_count;
- }
- }
-
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to find F12\n",
- __func__);
- return -EINVAL;
-
-f12_found:
- udg->query_base_addr = fd.query_base_addr | (page << 8);
- udg->control_base_addr = fd.ctrl_base_addr | (page << 8);
- udg->data_base_addr = fd.data_base_addr | (page << 8);
- udg->command_base_addr = fd.cmd_base_addr | (page << 8);
-
- retval = udg_reg_init();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to initialize user defined gesture registers\n",
- __func__);
- return retval;
- }
-
- udg->intr_mask = 0;
- intr_src = fd.intr_src_count;
- intr_off = intr_count % 8;
- for (ii = intr_off;
- ii < (intr_src + intr_off);
- ii++) {
- udg->intr_mask |= 1 << ii;
- }
-
- rmi4_data->intr_mask[0] |= udg->intr_mask;
-
- addr = rmi4_data->f01_ctrl_base_addr + 1;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- addr,
- &rmi4_data->intr_mask[0],
- sizeof(rmi4_data->intr_mask[0]));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set interrupt enable bit\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static void synaptics_rmi4_udg_attn(struct synaptics_rmi4_data *rmi4_data,
- unsigned char intr_mask)
-{
- if (!udg)
- return;
-
- if (udg->intr_mask & intr_mask)
- udg_report();
-
- return;
-}
-
-static int synaptics_rmi4_udg_init(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- unsigned char ii;
- unsigned char size;
- unsigned char attr_count;
- unsigned char param_count;
-
- if (udg) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Handle already exists\n",
- __func__);
- return 0;
- }
-
- udg = kzalloc(sizeof(*udg), GFP_KERNEL);
- if (!udg) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for udg\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- size = 0;
- for (ii = 0; ii < sizeof(ctrl_18_sub_size); ii++)
- size += ctrl_18_sub_size[ii];
- size += sizeof(struct udg_tuning);
- udg->ctrl_buf = kzalloc(size, GFP_KERNEL);
- if (!udg->ctrl_buf) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for ctrl_buf\n",
- __func__);
- retval = -ENOMEM;
- goto exit_free_udg;
- }
-
- udg->rmi4_data = rmi4_data;
-
- retval = udg_scan_pdt();
- if (retval < 0)
- goto exit_free_ctrl_buf;
-
- udg->template_data_buf = kzalloc(udg->template_data_size, GFP_KERNEL);
- if (!udg->template_data_buf) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for template_data_buf\n",
- __func__);
- retval = -ENOMEM;
- goto exit_free_ctrl_buf;
- }
-
-#ifdef STORE_GESTURES
- udg->storage_buf = kzalloc(
- udg->template_data_size * udg->gestures_to_store,
- GFP_KERNEL);
- if (!udg->storage_buf) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for storage_buf\n",
- __func__);
- kfree(udg->template_data_buf);
- retval = -ENOMEM;
- goto exit_free_ctrl_buf;
- }
-#endif
-
- udg->udg_dev = input_allocate_device();
- if (udg->udg_dev == NULL) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to allocate gesture device\n",
- __func__);
- retval = -ENOMEM;
- goto exit_free_template_data_buf;
- }
-
- udg->udg_dev->name = GESTURE_DRIVER_NAME;
- udg->udg_dev->phys = GESTURE_PHYS_NAME;
- udg->udg_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
- udg->udg_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
- udg->udg_dev->dev.parent = rmi4_data->pdev->dev.parent;
- input_set_drvdata(udg->udg_dev, rmi4_data);
-
- set_bit(EV_KEY, udg->udg_dev->evbit);
- set_bit(KEY_WAKEUP, udg->udg_dev->keybit);
- input_set_capability(udg->udg_dev, EV_KEY, KEY_WAKEUP);
-
- retval = input_register_device(udg->udg_dev);
- if (retval) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to register gesture device\n",
- __func__);
- input_free_device(udg->udg_dev);
- goto exit_free_template_data_buf;
- }
-
- udg->tuning_dir = kobject_create_and_add(TUNING_SYSFS_DIR_NAME,
- &udg->udg_dev->dev.kobj);
- if (!udg->tuning_dir) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create tuning sysfs directory\n",
- __func__);
- goto exit_unregister_input_device;
- }
-
- retval = sysfs_create_bin_file(&udg->udg_dev->dev.kobj, &template_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create template data bin file\n",
- __func__);
- goto exit_remove_sysfs_directory;
- }
-
- retval = sysfs_create_bin_file(&udg->udg_dev->dev.kobj, &trace_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create trace data bin file\n",
- __func__);
- goto exit_remove_bin_file;
- }
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- retval = sysfs_create_file(&udg->udg_dev->dev.kobj,
- &attrs[attr_count].attr);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs attributes\n",
- __func__);
- retval = -ENODEV;
- goto exit_remove_attrs;
- }
- }
-
- for (param_count = 0; param_count < ARRAY_SIZE(params); param_count++) {
- retval = sysfs_create_file(udg->tuning_dir,
- &params[param_count].attr);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create tuning parameters\n",
- __func__);
- retval = -ENODEV;
- goto exit_remove_params;
- }
- }
-
- retval = udg_engine_enable(true);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to enable gesture engine\n",
- __func__);
- goto exit_remove_params;
- }
-
- return 0;
-
-exit_remove_params:
- for (param_count--; param_count >= 0; param_count--) {
- sysfs_remove_file(udg->tuning_dir,
- &params[param_count].attr);
- }
-
-exit_remove_attrs:
- for (attr_count--; attr_count >= 0; attr_count--) {
- sysfs_remove_file(&udg->udg_dev->dev.kobj,
- &attrs[attr_count].attr);
- }
-
- sysfs_remove_bin_file(&udg->udg_dev->dev.kobj, &trace_data);
-
-exit_remove_bin_file:
- sysfs_remove_bin_file(&udg->udg_dev->dev.kobj, &template_data);
-
-exit_remove_sysfs_directory:
- kobject_put(udg->tuning_dir);
-
-exit_unregister_input_device:
- input_unregister_device(udg->udg_dev);
-
-exit_free_template_data_buf:
-#ifdef STORE_GESTURES
- kfree(udg->storage_buf);
-#endif
- kfree(udg->template_data_buf);
-
-exit_free_ctrl_buf:
- kfree(udg->ctrl_buf);
-
-exit_free_udg:
- kfree(udg);
- udg = NULL;
-
-exit:
- return retval;
-}
-
-static void synaptics_rmi4_udg_remove(struct synaptics_rmi4_data *rmi4_data)
-{
- unsigned char count;
-
- if (!udg)
- goto exit;
-
- for (count = 0; count < ARRAY_SIZE(params); count++) {
- sysfs_remove_file(udg->tuning_dir,
- &params[count].attr);
- }
-
- for (count = 0; count < ARRAY_SIZE(attrs); count++) {
- sysfs_remove_file(&udg->udg_dev->dev.kobj,
- &attrs[count].attr);
- }
-
- sysfs_remove_bin_file(&udg->udg_dev->dev.kobj, &trace_data);
- sysfs_remove_bin_file(&udg->udg_dev->dev.kobj, &template_data);
- kobject_put(udg->tuning_dir);
-
- input_unregister_device(udg->udg_dev);
-#ifdef STORE_GESTURES
- kfree(udg->storage_buf);
-#endif
- kfree(udg->template_data_buf);
- kfree(udg->trace_data_buf);
- kfree(udg->ctrl_buf);
- kfree(udg);
- udg = NULL;
-
-exit:
- complete(&udg_remove_complete);
-
- return;
-}
-
-static void synaptics_rmi4_udg_reset(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!udg) {
- synaptics_rmi4_udg_init(rmi4_data);
- return;
- }
-
- udg_scan_pdt();
- udg_engine_enable(true);
-#ifdef STORE_GESTURES
- udg_write_template_data();
- udg_write_valid_data();
-#endif
-
- return;
-}
-
-static void synaptics_rmi4_udg_reinit(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!udg)
- return;
-
- udg_engine_enable(true);
-#ifdef STORE_GESTURES
- udg_write_template_data();
- udg_write_valid_data();
-#endif
-
- return;
-}
-
-static void synaptics_rmi4_udg_e_suspend(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!udg)
- return;
-
- rmi4_data->sleep_enable(rmi4_data, false);
- rmi4_data->irq_enable(rmi4_data, true, false);
- enable_irq_wake(rmi4_data->irq);
-
- udg_engine_enable(true);
- udg_detection_enable(true);
-
- return;
-}
-
-static void synaptics_rmi4_udg_suspend(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!udg)
- return;
-
- rmi4_data->sleep_enable(rmi4_data, false);
- rmi4_data->irq_enable(rmi4_data, true, false);
- enable_irq_wake(rmi4_data->irq);
-
- udg_engine_enable(true);
- udg_detection_enable(true);
-
- return;
-}
-
-static void synaptics_rmi4_udg_resume(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!udg)
- return;
-
- disable_irq_wake(rmi4_data->irq);
- udg_detection_enable(false);
-
- return;
-}
-
-static void synaptics_rmi4_udg_l_resume(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!udg)
- return;
-
- disable_irq_wake(rmi4_data->irq);
- udg_detection_enable(false);
-
- return;
-}
-
-static struct synaptics_rmi4_exp_fn gesture_module = {
- .fn_type = RMI_GESTURE,
- .init = synaptics_rmi4_udg_init,
- .remove = synaptics_rmi4_udg_remove,
- .reset = synaptics_rmi4_udg_reset,
- .reinit = synaptics_rmi4_udg_reinit,
- .early_suspend = synaptics_rmi4_udg_e_suspend,
- .suspend = synaptics_rmi4_udg_suspend,
- .resume = synaptics_rmi4_udg_resume,
- .late_resume = synaptics_rmi4_udg_l_resume,
- .attn = synaptics_rmi4_udg_attn,
-};
-
-static int __init rmi4_gesture_module_init(void)
-{
- synaptics_rmi4_new_function(&gesture_module, true);
-
- return 0;
-}
-
-static void __exit rmi4_gesture_module_exit(void)
-{
- synaptics_rmi4_new_function(&gesture_module, false);
-
- wait_for_completion(&udg_remove_complete);
-
- return;
-}
-
-module_init(rmi4_gesture_module_init);
-module_exit(rmi4_gesture_module_exit);
-
-MODULE_AUTHOR("Synaptics, Inc.");
-MODULE_DESCRIPTION("Synaptics DSX User Defined Gesture Module");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
deleted file mode 100644
index 563ce16885b3..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_i2c.c
+++ /dev/null
@@ -1,712 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- * 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 as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/types.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx_v2_6.h>
-#include "synaptics_dsx_core.h"
-
-#define SYN_I2C_RETRY_TIMES 10
-
-/*
-#define I2C_BURST_LIMIT 255
-*/
-/*
-#define XFER_MSGS_LIMIT 8
-*/
-
-static unsigned char *wr_buf;
-
-static struct synaptics_dsx_hw_interface hw_if;
-
-static struct platform_device *synaptics_dsx_i2c_device;
-
-#ifdef CONFIG_OF
-static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
-{
- int retval;
- u32 value;
- const char *name;
- struct property *prop;
- struct device_node *np = dev->of_node;
-
- bdata->irq_gpio = of_get_named_gpio_flags(np,
- "synaptics,irq-gpio", 0,
- (enum of_gpio_flags *)&bdata->irq_flags);
-
- retval = of_property_read_u32(np, "synaptics,irq-on-state",
- &value);
- if (retval < 0)
- bdata->irq_on_state = 0;
- else
- bdata->irq_on_state = value;
-
- bdata->resume_in_workqueue = of_property_read_bool(np,
- "synaptics,resume-in-workqueue");
-
- retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
- if (retval < 0)
- bdata->pwr_reg_name = NULL;
- else
- bdata->pwr_reg_name = name;
-
- retval = of_property_read_string(np, "synaptics,bus-reg-name", &name);
- if (retval < 0)
- bdata->bus_reg_name = NULL;
- else
- bdata->bus_reg_name = name;
-
- prop = of_find_property(np, "synaptics,power-gpio", NULL);
- if (prop && prop->length) {
- bdata->power_gpio = of_get_named_gpio_flags(np,
- "synaptics,power-gpio", 0, NULL);
- retval = of_property_read_u32(np, "synaptics,power-on-state",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,power-on-state property\n",
- __func__);
- return retval;
- } else {
- bdata->power_on_state = value;
- }
- } else {
- bdata->power_gpio = -1;
- }
-
- prop = of_find_property(np, "synaptics,power-delay-ms", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,power-delay-ms",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,power-delay-ms property\n",
- __func__);
- return retval;
- } else {
- bdata->power_delay_ms = value;
- }
- } else {
- bdata->power_delay_ms = 0;
- }
-
- prop = of_find_property(np, "synaptics,reset-gpio", NULL);
- if (prop && prop->length) {
- bdata->reset_gpio = of_get_named_gpio_flags(np,
- "synaptics,reset-gpio", 0, NULL);
- retval = of_property_read_u32(np, "synaptics,reset-on-state",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,reset-on-state property\n",
- __func__);
- return retval;
- } else {
- bdata->reset_on_state = value;
- }
- retval = of_property_read_u32(np, "synaptics,reset-active-ms",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,reset-active-ms property\n",
- __func__);
- return retval;
- } else {
- bdata->reset_active_ms = value;
- }
- } else {
- bdata->reset_gpio = -1;
- }
-
- prop = of_find_property(np, "synaptics,reset-delay-ms", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,reset-delay-ms",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,reset-delay-ms property\n",
- __func__);
- return retval;
- } else {
- bdata->reset_delay_ms = value;
- }
- } else {
- bdata->reset_delay_ms = 0;
- }
-
- prop = of_find_property(np, "synaptics,max-y-for-2d", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,max-y-for-2d",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,max-y-for-2d property\n",
- __func__);
- return retval;
- } else {
- bdata->max_y_for_2d = value;
- }
- } else {
- bdata->max_y_for_2d = -1;
- }
-
- prop = of_find_property(np, "synaptics,swap-axes", NULL);
- bdata->swap_axes = prop > 0 ? true : false;
-
- prop = of_find_property(np, "synaptics,x-flip", NULL);
- bdata->x_flip = prop > 0 ? true : false;
-
- prop = of_find_property(np, "synaptics,y-flip", NULL);
- bdata->y_flip = prop > 0 ? true : false;
-
- prop = of_find_property(np, "synaptics,ub-i2c-addr", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,ub-i2c-addr",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,ub-i2c-addr property\n",
- __func__);
- return retval;
- } else {
- bdata->ub_i2c_addr = (unsigned short)value;
- }
- } else {
- bdata->ub_i2c_addr = -1;
- }
-
- prop = of_find_property(np, "synaptics,cap-button-codes", NULL);
- if (prop && prop->length) {
- bdata->cap_button_map->map = devm_kzalloc(dev,
- prop->length,
- GFP_KERNEL);
- if (!bdata->cap_button_map->map)
- return -ENOMEM;
- bdata->cap_button_map->nbuttons = prop->length / sizeof(u32);
- retval = of_property_read_u32_array(np,
- "synaptics,cap-button-codes",
- bdata->cap_button_map->map,
- bdata->cap_button_map->nbuttons);
- if (retval < 0) {
- bdata->cap_button_map->nbuttons = 0;
- bdata->cap_button_map->map = NULL;
- }
- } else {
- bdata->cap_button_map->nbuttons = 0;
- bdata->cap_button_map->map = NULL;
- }
-
- prop = of_find_property(np, "synaptics,vir-button-codes", NULL);
- if (prop && prop->length) {
- bdata->vir_button_map->map = devm_kzalloc(dev,
- prop->length,
- GFP_KERNEL);
- if (!bdata->vir_button_map->map)
- return -ENOMEM;
- bdata->vir_button_map->nbuttons = prop->length / sizeof(u32);
- bdata->vir_button_map->nbuttons /= 5;
- retval = of_property_read_u32_array(np,
- "synaptics,vir-button-codes",
- bdata->vir_button_map->map,
- bdata->vir_button_map->nbuttons * 5);
- if (retval < 0) {
- bdata->vir_button_map->nbuttons = 0;
- bdata->vir_button_map->map = NULL;
- }
- } else {
- bdata->vir_button_map->nbuttons = 0;
- bdata->vir_button_map->map = NULL;
- }
-
- return 0;
-}
-#endif
-
-static int synaptics_rmi4_i2c_alloc_buf(struct synaptics_rmi4_data *rmi4_data,
- unsigned int count)
-{
- static unsigned int buf_size;
-
- if (count > buf_size) {
- if (buf_size)
- kfree(wr_buf);
- wr_buf = kzalloc(count, GFP_KERNEL);
- if (!wr_buf) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for buffer\n",
- __func__);
- buf_size = 0;
- return -ENOMEM;
- }
- buf_size = count;
- }
-
- return 0;
-}
-
-static void synaptics_rmi4_i2c_check_addr(struct synaptics_rmi4_data *rmi4_data,
- struct i2c_client *i2c)
-{
- if (hw_if.board_data->ub_i2c_addr == -1)
- return;
-
- if (hw_if.board_data->i2c_addr == i2c->addr)
- hw_if.board_data->i2c_addr = hw_if.board_data->ub_i2c_addr;
- else
- hw_if.board_data->i2c_addr = i2c->addr;
-
- return;
-}
-
-static int synaptics_rmi4_i2c_set_page(struct synaptics_rmi4_data *rmi4_data,
- unsigned short addr)
-{
- int retval = 0;
- unsigned char retry;
- unsigned char buf[PAGE_SELECT_LEN];
- unsigned char page;
- struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
- struct i2c_msg msg[1];
-
- msg[0].addr = hw_if.board_data->i2c_addr;
- msg[0].flags = 0;
- msg[0].len = PAGE_SELECT_LEN;
- msg[0].buf = buf;
-
- page = ((addr >> 8) & MASK_8BIT);
- buf[0] = MASK_8BIT;
- buf[1] = page;
-
- if (page != rmi4_data->current_page) {
- for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
- if (i2c_transfer(i2c->adapter, msg, 1) == 1) {
- rmi4_data->current_page = page;
- retval = PAGE_SELECT_LEN;
- break;
- }
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: I2C retry %d\n",
- __func__, retry + 1);
- msleep(20);
-
- if (retry == SYN_I2C_RETRY_TIMES / 2) {
- synaptics_rmi4_i2c_check_addr(rmi4_data, i2c);
- msg[0].addr = hw_if.board_data->i2c_addr;
- }
- }
- } else {
- retval = PAGE_SELECT_LEN;
- }
-
- return retval;
-}
-
-static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
- unsigned short addr, unsigned char *data, unsigned short length)
-{
- int retval;
- unsigned char retry;
- unsigned char buf;
-#ifdef I2C_BURST_LIMIT
- unsigned char ii;
- unsigned char rd_msgs = ((length - 1) / I2C_BURST_LIMIT) + 1;
-#else
- unsigned char rd_msgs = 1;
-#endif
- unsigned char index = 0;
- unsigned char xfer_msgs;
- unsigned char remaining_msgs;
- unsigned short i2c_addr;
- unsigned short data_offset = 0;
- unsigned short remaining_length = length;
- struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
- struct i2c_adapter *adap = i2c->adapter;
- struct i2c_msg msg[rd_msgs + 1];
-
- mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr);
- if (retval != PAGE_SELECT_LEN) {
- retval = -EIO;
- goto exit;
- }
-
- msg[0].addr = hw_if.board_data->i2c_addr;
- msg[0].flags = 0;
- msg[0].len = 1;
- msg[0].buf = &buf;
-
-#ifdef I2C_BURST_LIMIT
- for (ii = 0; ii < (rd_msgs - 1); ii++) {
- msg[ii + 1].addr = hw_if.board_data->i2c_addr;
- msg[ii + 1].flags = I2C_M_RD;
- msg[ii + 1].len = I2C_BURST_LIMIT;
- msg[ii + 1].buf = &data[data_offset];
- data_offset += I2C_BURST_LIMIT;
- remaining_length -= I2C_BURST_LIMIT;
- }
-#endif
-
- msg[rd_msgs].addr = hw_if.board_data->i2c_addr;
- msg[rd_msgs].flags = I2C_M_RD;
- msg[rd_msgs].len = remaining_length;
- msg[rd_msgs].buf = &data[data_offset];
-
- buf = addr & MASK_8BIT;
-
- remaining_msgs = rd_msgs + 1;
-
- while (remaining_msgs) {
-#ifdef XFER_MSGS_LIMIT
- if (remaining_msgs > XFER_MSGS_LIMIT)
- xfer_msgs = XFER_MSGS_LIMIT;
- else
- xfer_msgs = remaining_msgs;
-#else
- xfer_msgs = remaining_msgs;
-#endif
- for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
- retval = i2c_transfer(adap, &msg[index], xfer_msgs);
- if (retval == xfer_msgs)
- break;
-
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: I2C retry %d\n",
- __func__, retry + 1);
- msleep(20);
-
- if (retry == SYN_I2C_RETRY_TIMES / 2) {
- synaptics_rmi4_i2c_check_addr(rmi4_data, i2c);
- i2c_addr = hw_if.board_data->i2c_addr;
- msg[0].addr = i2c_addr;
-#ifdef I2C_BURST_LIMIT
- for (ii = 0; ii < (rd_msgs - 1); ii++)
- msg[ii + 1].addr = i2c_addr;
-#endif
- msg[rd_msgs].addr = i2c_addr;
- }
- }
-
- if (retry == SYN_I2C_RETRY_TIMES) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: I2C read over retry limit\n",
- __func__);
- retval = -EIO;
- goto exit;
- }
-
- remaining_msgs -= xfer_msgs;
- index += xfer_msgs;
- }
-
- retval = length;
-
-exit:
- mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- return retval;
-}
-
-static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
- unsigned short addr, unsigned char *data, unsigned short length)
-{
- int retval;
- unsigned char retry;
- struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
- struct i2c_msg msg[1];
-
- mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- retval = synaptics_rmi4_i2c_alloc_buf(rmi4_data, length + 1);
- if (retval < 0)
- goto exit;
-
- retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr);
- if (retval != PAGE_SELECT_LEN) {
- retval = -EIO;
- goto exit;
- }
-
- msg[0].addr = hw_if.board_data->i2c_addr;
- msg[0].flags = 0;
- msg[0].len = length + 1;
- msg[0].buf = wr_buf;
-
- wr_buf[0] = addr & MASK_8BIT;
- retval = secure_memcpy(&wr_buf[1], length, &data[0], length, length);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy data\n",
- __func__);
- goto exit;
- }
-
- for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
- if (i2c_transfer(i2c->adapter, msg, 1) == 1) {
- retval = length;
- break;
- }
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: I2C retry %d\n",
- __func__, retry + 1);
- msleep(20);
-
- if (retry == SYN_I2C_RETRY_TIMES / 2) {
- synaptics_rmi4_i2c_check_addr(rmi4_data, i2c);
- msg[0].addr = hw_if.board_data->i2c_addr;
- }
- }
-
- if (retry == SYN_I2C_RETRY_TIMES) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: I2C write over retry limit\n",
- __func__);
- retval = -EIO;
- }
-
-exit:
- mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- return retval;
-}
-
-#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
-static int synaptics_rmi4_clk_prepare_enable(
- struct synaptics_rmi4_data *rmi4_data)
-{
- int ret;
-
- ret = clk_prepare_enable(rmi4_data->iface_clk);
- if (ret) {
- dev_err(rmi4_data->pdev->dev.parent,
- "error on clk_prepare_enable(iface_clk):%d\n", ret);
- return ret;
- }
-
- ret = clk_prepare_enable(rmi4_data->core_clk);
- if (ret) {
- clk_disable_unprepare(rmi4_data->iface_clk);
- dev_err(rmi4_data->pdev->dev.parent,
- "error clk_prepare_enable(core_clk):%d\n", ret);
- }
- return ret;
-}
-
-static void synaptics_rmi4_clk_disable_unprepare(
- struct synaptics_rmi4_data *rmi4_data)
-{
- clk_disable_unprepare(rmi4_data->core_clk);
- clk_disable_unprepare(rmi4_data->iface_clk);
-}
-
-static int synaptics_rmi4_i2c_get(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
-
- mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
- retval = pm_runtime_get_sync(i2c->adapter->dev.parent);
- if (retval >= 0 && rmi4_data->core_clk != NULL &&
- rmi4_data->iface_clk != NULL) {
- retval = synaptics_rmi4_clk_prepare_enable(rmi4_data);
- if (retval)
- pm_runtime_put_sync(i2c->adapter->dev.parent);
- }
- mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- return retval;
-}
-
-static void synaptics_rmi4_i2c_put(struct synaptics_rmi4_data *rmi4_data)
-{
- struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
-
- mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
- if (rmi4_data->core_clk != NULL && rmi4_data->iface_clk != NULL)
- synaptics_rmi4_clk_disable_unprepare(rmi4_data);
- pm_runtime_put_sync(i2c->adapter->dev.parent);
- mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
-}
-#endif
-
-static struct synaptics_dsx_bus_access bus_access = {
- .type = BUS_I2C,
- .read = synaptics_rmi4_i2c_read,
- .write = synaptics_rmi4_i2c_write,
-#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
- .get = synaptics_rmi4_i2c_get,
- .put = synaptics_rmi4_i2c_put,
-#endif
-};
-
-static void synaptics_rmi4_i2c_dev_release(struct device *dev)
-{
- kfree(synaptics_dsx_i2c_device);
-
- return;
-}
-
-static int synaptics_rmi4_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *dev_id)
-{
- int retval;
-
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA)) {
- dev_err(&client->dev,
- "%s: SMBus byte data commands not supported by host\n",
- __func__);
- return -EIO;
- }
-
- synaptics_dsx_i2c_device = kzalloc(
- sizeof(struct platform_device),
- GFP_KERNEL);
- if (!synaptics_dsx_i2c_device) {
- dev_err(&client->dev,
- "%s: Failed to allocate memory for synaptics_dsx_i2c_device\n",
- __func__);
- return -ENOMEM;
- }
-
-#ifdef CONFIG_OF
- if (client->dev.of_node) {
- hw_if.board_data = devm_kzalloc(&client->dev,
- sizeof(struct synaptics_dsx_board_data),
- GFP_KERNEL);
- if (!hw_if.board_data) {
- dev_err(&client->dev,
- "%s: Failed to allocate memory for board data\n",
- __func__);
- return -ENOMEM;
- }
- hw_if.board_data->cap_button_map = devm_kzalloc(&client->dev,
- sizeof(struct synaptics_dsx_button_map),
- GFP_KERNEL);
- if (!hw_if.board_data->cap_button_map) {
- dev_err(&client->dev,
- "%s: Failed to allocate memory for 0D button map\n",
- __func__);
- return -ENOMEM;
- }
- hw_if.board_data->vir_button_map = devm_kzalloc(&client->dev,
- sizeof(struct synaptics_dsx_button_map),
- GFP_KERNEL);
- if (!hw_if.board_data->vir_button_map) {
- dev_err(&client->dev,
- "%s: Failed to allocate memory for virtual button map\n",
- __func__);
- return -ENOMEM;
- }
- parse_dt(&client->dev, hw_if.board_data);
- }
-#else
- hw_if.board_data = client->dev.platform_data;
-#endif
-
- hw_if.bus_access = &bus_access;
- hw_if.board_data->i2c_addr = client->addr;
-
- synaptics_dsx_i2c_device->name = PLATFORM_DRIVER_NAME;
- synaptics_dsx_i2c_device->id = 0;
- synaptics_dsx_i2c_device->num_resources = 0;
- synaptics_dsx_i2c_device->dev.parent = &client->dev;
- synaptics_dsx_i2c_device->dev.platform_data = &hw_if;
- synaptics_dsx_i2c_device->dev.release = synaptics_rmi4_i2c_dev_release;
-
- retval = platform_device_register(synaptics_dsx_i2c_device);
- if (retval) {
- dev_err(&client->dev,
- "%s: Failed to register platform device\n",
- __func__);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int synaptics_rmi4_i2c_remove(struct i2c_client *client)
-{
- platform_device_unregister(synaptics_dsx_i2c_device);
-
- return 0;
-}
-
-static const struct i2c_device_id synaptics_rmi4_id_table[] = {
- {I2C_DRIVER_NAME, 0},
- {},
-};
-MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
-
-#ifdef CONFIG_OF
-static struct of_device_id synaptics_rmi4_of_match_table[] = {
- {
- .compatible = "synaptics,dsx-i2c",
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, synaptics_rmi4_of_match_table);
-#else
-#define synaptics_rmi4_of_match_table NULL
-#endif
-
-static struct i2c_driver synaptics_rmi4_i2c_driver = {
- .driver = {
- .name = I2C_DRIVER_NAME,
- .owner = THIS_MODULE,
- .of_match_table = synaptics_rmi4_of_match_table,
- },
- .probe = synaptics_rmi4_i2c_probe,
- .remove = synaptics_rmi4_i2c_remove,
- .id_table = synaptics_rmi4_id_table,
-};
-
-int synaptics_rmi4_bus_init_v26(void)
-{
- return i2c_add_driver(&synaptics_rmi4_i2c_driver);
-}
-EXPORT_SYMBOL(synaptics_rmi4_bus_init_v26);
-
-void synaptics_rmi4_bus_exit_v26(void)
-{
- kfree(wr_buf);
-
- i2c_del_driver(&synaptics_rmi4_i2c_driver);
-
- return;
-}
-EXPORT_SYMBOL(synaptics_rmi4_bus_exit_v26);
-
-MODULE_AUTHOR("Synaptics, Inc.");
-MODULE_DESCRIPTION("Synaptics DSX I2C Bus Support Module");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_proximity.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_proximity.c
deleted file mode 100644
index d9e27c306af5..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_proximity.c
+++ /dev/null
@@ -1,692 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx_v2_6.h>
-#include "synaptics_dsx_core.h"
-
-#define PROX_PHYS_NAME "synaptics_dsx/proximity"
-
-#define HOVER_Z_MAX (255)
-
-#define HOVERING_FINGER_EN (1 << 4)
-
-static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static struct device_attribute attrs[] = {
- __ATTR(hover_finger_en, (S_IRUGO | S_IWUGO),
- synaptics_rmi4_hover_finger_en_show,
- synaptics_rmi4_hover_finger_en_store),
-};
-
-struct synaptics_rmi4_f12_query_5 {
- union {
- struct {
- unsigned char size_of_query6;
- struct {
- unsigned char ctrl0_is_present:1;
- unsigned char ctrl1_is_present:1;
- unsigned char ctrl2_is_present:1;
- unsigned char ctrl3_is_present:1;
- unsigned char ctrl4_is_present:1;
- unsigned char ctrl5_is_present:1;
- unsigned char ctrl6_is_present:1;
- unsigned char ctrl7_is_present:1;
- } __packed;
- struct {
- unsigned char ctrl8_is_present:1;
- unsigned char ctrl9_is_present:1;
- unsigned char ctrl10_is_present:1;
- unsigned char ctrl11_is_present:1;
- unsigned char ctrl12_is_present:1;
- unsigned char ctrl13_is_present:1;
- unsigned char ctrl14_is_present:1;
- unsigned char ctrl15_is_present:1;
- } __packed;
- struct {
- unsigned char ctrl16_is_present:1;
- unsigned char ctrl17_is_present:1;
- unsigned char ctrl18_is_present:1;
- unsigned char ctrl19_is_present:1;
- unsigned char ctrl20_is_present:1;
- unsigned char ctrl21_is_present:1;
- unsigned char ctrl22_is_present:1;
- unsigned char ctrl23_is_present:1;
- } __packed;
- };
- unsigned char data[4];
- };
-};
-
-struct synaptics_rmi4_f12_query_8 {
- union {
- struct {
- unsigned char size_of_query9;
- struct {
- unsigned char data0_is_present:1;
- unsigned char data1_is_present:1;
- unsigned char data2_is_present:1;
- unsigned char data3_is_present:1;
- unsigned char data4_is_present:1;
- unsigned char data5_is_present:1;
- unsigned char data6_is_present:1;
- unsigned char data7_is_present:1;
- } __packed;
- };
- unsigned char data[2];
- };
-};
-
-struct prox_finger_data {
- union {
- struct {
- unsigned char object_type_and_status;
- unsigned char x_lsb;
- unsigned char x_msb;
- unsigned char y_lsb;
- unsigned char y_msb;
- unsigned char z;
- } __packed;
- unsigned char proximity_data[6];
- };
-};
-
-struct synaptics_rmi4_prox_handle {
- bool hover_finger_present;
- bool hover_finger_en;
- unsigned char intr_mask;
- unsigned short query_base_addr;
- unsigned short control_base_addr;
- unsigned short data_base_addr;
- unsigned short command_base_addr;
- unsigned short hover_finger_en_addr;
- unsigned short hover_finger_data_addr;
- struct input_dev *prox_dev;
- struct prox_finger_data *finger_data;
- struct synaptics_rmi4_data *rmi4_data;
-};
-
-static struct synaptics_rmi4_prox_handle *prox;
-
-DECLARE_COMPLETION(prox_remove_complete);
-
-static void prox_hover_finger_lift(void)
-{
- input_report_key(prox->prox_dev, BTN_TOUCH, 0);
- input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 0);
- input_sync(prox->prox_dev);
- prox->hover_finger_present = false;
-
- return;
-}
-
-static void prox_hover_finger_report(void)
-{
- int retval;
- int x;
- int y;
- int z;
- struct prox_finger_data *data;
- struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
-
- data = prox->finger_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- prox->hover_finger_data_addr,
- data->proximity_data,
- sizeof(data->proximity_data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read hovering finger data\n",
- __func__);
- return;
- }
-
- if (data->object_type_and_status != F12_HOVERING_FINGER_STATUS) {
- if (prox->hover_finger_present)
- prox_hover_finger_lift();
-
- return;
- }
-
- x = (data->x_msb << 8) | (data->x_lsb);
- y = (data->y_msb << 8) | (data->y_lsb);
- z = HOVER_Z_MAX - data->z;
-
- input_report_key(prox->prox_dev, BTN_TOUCH, 0);
- input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 1);
- input_report_abs(prox->prox_dev, ABS_X, x);
- input_report_abs(prox->prox_dev, ABS_Y, y);
- input_report_abs(prox->prox_dev, ABS_DISTANCE, z);
-
- input_sync(prox->prox_dev);
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: x = %d y = %d z = %d\n",
- __func__, x, y, z);
-
- prox->hover_finger_present = true;
-
- return;
-}
-
-static int prox_set_hover_finger_en(void)
-{
- int retval;
- unsigned char object_report_enable;
- struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- prox->hover_finger_en_addr,
- &object_report_enable,
- sizeof(object_report_enable));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read from object report enable register\n",
- __func__);
- return retval;
- }
-
- if (prox->hover_finger_en)
- object_report_enable |= HOVERING_FINGER_EN;
- else
- object_report_enable &= ~HOVERING_FINGER_EN;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- prox->hover_finger_en_addr,
- &object_report_enable,
- sizeof(object_report_enable));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write to object report enable register\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static void prox_set_params(void)
-{
- input_set_abs_params(prox->prox_dev, ABS_X, 0,
- prox->rmi4_data->sensor_max_x, 0, 0);
- input_set_abs_params(prox->prox_dev, ABS_Y, 0,
- prox->rmi4_data->sensor_max_y, 0, 0);
- input_set_abs_params(prox->prox_dev, ABS_DISTANCE, 0,
- HOVER_Z_MAX, 0, 0);
-
- return;
-}
-
-static int prox_reg_init(void)
-{
- int retval;
- unsigned char ctrl_23_offset;
- unsigned char data_1_offset;
- struct synaptics_rmi4_f12_query_5 query_5;
- struct synaptics_rmi4_f12_query_8 query_8;
- struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- prox->query_base_addr + 5,
- query_5.data,
- sizeof(query_5.data));
- if (retval < 0)
- return retval;
-
- ctrl_23_offset = query_5.ctrl0_is_present +
- query_5.ctrl1_is_present +
- query_5.ctrl2_is_present +
- query_5.ctrl3_is_present +
- query_5.ctrl4_is_present +
- query_5.ctrl5_is_present +
- query_5.ctrl6_is_present +
- query_5.ctrl7_is_present +
- query_5.ctrl8_is_present +
- query_5.ctrl9_is_present +
- query_5.ctrl10_is_present +
- query_5.ctrl11_is_present +
- query_5.ctrl12_is_present +
- query_5.ctrl13_is_present +
- query_5.ctrl14_is_present +
- query_5.ctrl15_is_present +
- query_5.ctrl16_is_present +
- query_5.ctrl17_is_present +
- query_5.ctrl18_is_present +
- query_5.ctrl19_is_present +
- query_5.ctrl20_is_present +
- query_5.ctrl21_is_present +
- query_5.ctrl22_is_present;
-
- prox->hover_finger_en_addr = prox->control_base_addr + ctrl_23_offset;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- prox->query_base_addr + 8,
- query_8.data,
- sizeof(query_8.data));
- if (retval < 0)
- return retval;
-
- data_1_offset = query_8.data0_is_present;
- prox->hover_finger_data_addr = prox->data_base_addr + data_1_offset;
-
- return retval;
-}
-
-static int prox_scan_pdt(void)
-{
- int retval;
- unsigned char ii;
- unsigned char page;
- unsigned char intr_count = 0;
- unsigned char intr_off;
- unsigned char intr_src;
- unsigned short addr;
- struct synaptics_rmi4_fn_desc fd;
- struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
-
- for (page = 0; page < PAGES_TO_SERVICE; page++) {
- for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
- addr |= (page << 8);
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- addr,
- (unsigned char *)&fd,
- sizeof(fd));
- if (retval < 0)
- return retval;
-
- addr &= ~(MASK_8BIT << 8);
-
- if (fd.fn_number) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Found F%02x\n",
- __func__, fd.fn_number);
- switch (fd.fn_number) {
- case SYNAPTICS_RMI4_F12:
- goto f12_found;
- break;
- }
- } else {
- break;
- }
-
- intr_count += fd.intr_src_count;
- }
- }
-
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to find F12\n",
- __func__);
- return -EINVAL;
-
-f12_found:
- prox->query_base_addr = fd.query_base_addr | (page << 8);
- prox->control_base_addr = fd.ctrl_base_addr | (page << 8);
- prox->data_base_addr = fd.data_base_addr | (page << 8);
- prox->command_base_addr = fd.cmd_base_addr | (page << 8);
-
- retval = prox_reg_init();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to initialize proximity registers\n",
- __func__);
- return retval;
- }
-
- prox->intr_mask = 0;
- intr_src = fd.intr_src_count;
- intr_off = intr_count % 8;
- for (ii = intr_off;
- ii < (intr_src + intr_off);
- ii++) {
- prox->intr_mask |= 1 << ii;
- }
-
- rmi4_data->intr_mask[0] |= prox->intr_mask;
-
- addr = rmi4_data->f01_ctrl_base_addr + 1;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- addr,
- &(rmi4_data->intr_mask[0]),
- sizeof(rmi4_data->intr_mask[0]));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set interrupt enable bit\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- if (!prox)
- return -ENODEV;
-
- return snprintf(buf, PAGE_SIZE, "%u\n",
- prox->hover_finger_en);
-}
-
-static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
-
- if (!prox)
- return -ENODEV;
-
- if (sscanf(buf, "%x", &input) != 1)
- return -EINVAL;
-
- if (input == 1)
- prox->hover_finger_en = true;
- else if (input == 0)
- prox->hover_finger_en = false;
- else
- return -EINVAL;
-
- retval = prox_set_hover_finger_en();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to change hovering finger enable setting\n",
- __func__);
- return retval;
- }
-
- return count;
-}
-
-int synaptics_rmi4_prox_hover_finger_en(bool enable)
-{
- int retval;
-
- if (!prox)
- return -ENODEV;
-
- prox->hover_finger_en = enable;
-
- retval = prox_set_hover_finger_en();
- if (retval < 0)
- return retval;
-
- return 0;
-}
-EXPORT_SYMBOL(synaptics_rmi4_prox_hover_finger_en);
-
-static void synaptics_rmi4_prox_attn(struct synaptics_rmi4_data *rmi4_data,
- unsigned char intr_mask)
-{
- if (!prox)
- return;
-
- if (prox->intr_mask & intr_mask)
- prox_hover_finger_report();
-
- return;
-}
-
-static int synaptics_rmi4_prox_init(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- unsigned char attr_count;
-
- if (prox) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Handle already exists\n",
- __func__);
- return 0;
- }
-
- prox = kzalloc(sizeof(*prox), GFP_KERNEL);
- if (!prox) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for prox\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- prox->finger_data = kzalloc(sizeof(*(prox->finger_data)), GFP_KERNEL);
- if (!prox->finger_data) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for finger_data\n",
- __func__);
- retval = -ENOMEM;
- goto exit_free_prox;
- }
-
- prox->rmi4_data = rmi4_data;
-
- retval = prox_scan_pdt();
- if (retval < 0)
- goto exit_free_finger_data;
-
- prox->hover_finger_en = true;
-
- retval = prox_set_hover_finger_en();
- if (retval < 0)
- return retval;
-
- prox->prox_dev = input_allocate_device();
- if (prox->prox_dev == NULL) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to allocate proximity device\n",
- __func__);
- retval = -ENOMEM;
- goto exit_free_finger_data;
- }
-
- prox->prox_dev->name = PROXIMITY_DRIVER_NAME;
- prox->prox_dev->phys = PROX_PHYS_NAME;
- prox->prox_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
- prox->prox_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
- prox->prox_dev->dev.parent = rmi4_data->pdev->dev.parent;
- input_set_drvdata(prox->prox_dev, rmi4_data);
-
- set_bit(EV_KEY, prox->prox_dev->evbit);
- set_bit(EV_ABS, prox->prox_dev->evbit);
- set_bit(BTN_TOUCH, prox->prox_dev->keybit);
- set_bit(BTN_TOOL_FINGER, prox->prox_dev->keybit);
-#ifdef INPUT_PROP_DIRECT
- set_bit(INPUT_PROP_DIRECT, prox->prox_dev->propbit);
-#endif
-
- prox_set_params();
-
- retval = input_register_device(prox->prox_dev);
- if (retval) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to register proximity device\n",
- __func__);
- goto exit_free_input_device;
- }
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs attributes\n",
- __func__);
- goto exit_free_sysfs;
- }
- }
-
- return 0;
-
-exit_free_sysfs:
- for (attr_count--; attr_count >= 0; attr_count--) {
- sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- }
-
- input_unregister_device(prox->prox_dev);
- prox->prox_dev = NULL;
-
-exit_free_input_device:
- if (prox->prox_dev)
- input_free_device(prox->prox_dev);
-
-exit_free_finger_data:
- kfree(prox->finger_data);
-
-exit_free_prox:
- kfree(prox);
- prox = NULL;
-
-exit:
- return retval;
-}
-
-static void synaptics_rmi4_prox_remove(struct synaptics_rmi4_data *rmi4_data)
-{
- unsigned char attr_count;
-
- if (!prox)
- goto exit;
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
- &attrs[attr_count].attr);
- }
-
- input_unregister_device(prox->prox_dev);
- kfree(prox->finger_data);
- kfree(prox);
- prox = NULL;
-
-exit:
- complete(&prox_remove_complete);
-
- return;
-}
-
-static void synaptics_rmi4_prox_reset(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!prox) {
- synaptics_rmi4_prox_init(rmi4_data);
- return;
- }
-
- prox_hover_finger_lift();
-
- prox_scan_pdt();
-
- prox_set_hover_finger_en();
-
- return;
-}
-
-static void synaptics_rmi4_prox_reinit(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!prox)
- return;
-
- prox_hover_finger_lift();
-
- prox_set_hover_finger_en();
-
- return;
-}
-
-static void synaptics_rmi4_prox_e_suspend(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!prox)
- return;
-
- prox_hover_finger_lift();
-
- return;
-}
-
-static void synaptics_rmi4_prox_suspend(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!prox)
- return;
-
- prox_hover_finger_lift();
-
- return;
-}
-
-static struct synaptics_rmi4_exp_fn proximity_module = {
- .fn_type = RMI_PROXIMITY,
- .init = synaptics_rmi4_prox_init,
- .remove = synaptics_rmi4_prox_remove,
- .reset = synaptics_rmi4_prox_reset,
- .reinit = synaptics_rmi4_prox_reinit,
- .early_suspend = synaptics_rmi4_prox_e_suspend,
- .suspend = synaptics_rmi4_prox_suspend,
- .resume = NULL,
- .late_resume = NULL,
- .attn = synaptics_rmi4_prox_attn,
-};
-
-static int __init rmi4_proximity_module_init(void)
-{
- synaptics_rmi4_new_function(&proximity_module, true);
-
- return 0;
-}
-
-static void __exit rmi4_proximity_module_exit(void)
-{
- synaptics_rmi4_new_function(&proximity_module, false);
-
- wait_for_completion(&prox_remove_complete);
-
- return;
-}
-
-module_init(rmi4_proximity_module_init);
-module_exit(rmi4_proximity_module_exit);
-
-MODULE_AUTHOR("Synaptics, Inc.");
-MODULE_DESCRIPTION("Synaptics DSX Proximity Module");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c
deleted file mode 100644
index 111b26c7b759..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_dev.c
+++ /dev/null
@@ -1,1058 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/gpio.h>
-#include <linux/uaccess.h>
-#include <linux/cdev.h>
-#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx_v2_6.h>
-#include "synaptics_dsx_core.h"
-
-#define CHAR_DEVICE_NAME "rmi"
-#define DEVICE_CLASS_NAME "rmidev"
-#define SYSFS_FOLDER_NAME "rmidev"
-#define DEV_NUMBER 1
-#define REG_ADDR_LIMIT 0xFFFF
-
-static ssize_t rmidev_sysfs_data_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
-
-static ssize_t rmidev_sysfs_data_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
-
-static ssize_t rmidev_sysfs_open_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t rmidev_sysfs_release_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t rmidev_sysfs_attn_state_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t rmidev_sysfs_pid_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t rmidev_sysfs_pid_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t rmidev_sysfs_term_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t rmidev_sysfs_intr_mask_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t rmidev_sysfs_intr_mask_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t rmidev_sysfs_concurrent_show(struct device *dev,
- struct device_attribute *attr, char *buf);
-
-static ssize_t rmidev_sysfs_concurrent_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-struct rmidev_handle {
- dev_t dev_no;
- pid_t pid;
- unsigned char intr_mask;
- unsigned char *tmpbuf;
- unsigned int tmpbuf_size;
- struct device dev;
- struct synaptics_rmi4_data *rmi4_data;
- struct kobject *sysfs_dir;
- struct siginfo interrupt_signal;
- struct siginfo terminate_signal;
- struct task_struct *task;
- void *data;
- bool irq_enabled;
- bool concurrent;
-};
-
-struct rmidev_data {
- int ref_count;
- struct cdev main_dev;
- struct class *device_class;
- struct mutex file_mutex;
- struct rmidev_handle *rmi_dev;
-};
-
-static struct bin_attribute attr_data = {
- .attr = {
- .name = "data",
- .mode = (S_IRUGO | S_IWUSR),
- },
- .size = 0,
- .read = rmidev_sysfs_data_show,
- .write = rmidev_sysfs_data_store,
-};
-
-static struct device_attribute attrs[] = {
- __ATTR(open, S_IWUSR | S_IWGRP,
- NULL,
- rmidev_sysfs_open_store),
- __ATTR(release, S_IWUSR | S_IWGRP,
- NULL,
- rmidev_sysfs_release_store),
- __ATTR(attn_state, S_IRUGO,
- rmidev_sysfs_attn_state_show,
- NULL),
- __ATTR(pid, S_IRUGO | S_IRUGO | S_IWUSR | S_IWGRP,
- rmidev_sysfs_pid_show,
- rmidev_sysfs_pid_store),
- __ATTR(term, S_IWUSR | S_IWGRP,
- NULL,
- rmidev_sysfs_term_store),
- __ATTR(intr_mask, S_IRUGO,
- rmidev_sysfs_intr_mask_show,
- rmidev_sysfs_intr_mask_store),
- __ATTR(concurrent, S_IRUGO,
- rmidev_sysfs_concurrent_show,
- rmidev_sysfs_concurrent_store),
-};
-
-static int rmidev_major_num;
-
-static struct class *rmidev_device_class;
-
-static struct rmidev_handle *rmidev;
-
-DECLARE_COMPLETION(rmidev_remove_complete_v26);
-
-static irqreturn_t rmidev_sysfs_irq(int irq, void *data)
-{
- struct synaptics_rmi4_data *rmi4_data = data;
-
- sysfs_notify(&rmi4_data->input_dev->dev.kobj,
- SYSFS_FOLDER_NAME, "attn_state");
-
- return IRQ_HANDLED;
-}
-
-static int rmidev_sysfs_irq_enable(struct synaptics_rmi4_data *rmi4_data,
- bool enable)
-{
- int retval = 0;
- unsigned char intr_status[MAX_INTR_REGISTERS];
- unsigned long irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
- IRQF_ONESHOT;
-
- if (enable) {
- if (rmidev->irq_enabled)
- return retval;
-
- /* Clear interrupts first */
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_data_base_addr + 1,
- intr_status,
- rmi4_data->num_of_intr_regs);
- if (retval < 0)
- return retval;
-
- retval = request_threaded_irq(rmi4_data->irq, NULL,
- rmidev_sysfs_irq, irq_flags,
- PLATFORM_DRIVER_NAME, rmi4_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create irq thread\n",
- __func__);
- return retval;
- }
-
- rmidev->irq_enabled = true;
- } else {
- if (rmidev->irq_enabled) {
- disable_irq(rmi4_data->irq);
- free_irq(rmi4_data->irq, rmi4_data);
- rmidev->irq_enabled = false;
- }
- }
-
- return retval;
-}
-
-static ssize_t rmidev_sysfs_data_show(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
-{
- int retval;
- unsigned char intr_status = 0;
- unsigned int length = (unsigned int)count;
- unsigned short address = (unsigned short)pos;
- struct synaptics_rmi4_fn *fhandler;
- struct synaptics_rmi4_device_info *rmi;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- rmi = &(rmi4_data->rmi4_mod_info);
-
- if (length > (REG_ADDR_LIMIT - address)) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Out of register map limit\n",
- __func__);
- return -EINVAL;
- }
-
- if (length) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- address,
- (unsigned char *)buf,
- length);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read data\n",
- __func__);
- return retval;
- }
- } else {
- return -EINVAL;
- }
-
- if (!rmidev->concurrent)
- goto exit;
-
- if (address != rmi4_data->f01_data_base_addr)
- goto exit;
-
- if (length <= 1)
- goto exit;
-
- intr_status = buf[1];
-
- if (!list_empty(&rmi->support_fn_list)) {
- list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- if (fhandler->num_of_data_sources) {
- if (fhandler->intr_mask & intr_status) {
- rmi4_data->report_touch(rmi4_data,
- fhandler);
- }
- }
- }
- }
-
-exit:
- return length;
-}
-
-static ssize_t rmidev_sysfs_data_store(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
-{
- int retval;
- unsigned int length = (unsigned int)count;
- unsigned short address = (unsigned short)pos;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- if (length > (REG_ADDR_LIMIT - address)) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Out of register map limit\n",
- __func__);
- return -EINVAL;
- }
-
- if (length) {
- retval = synaptics_rmi4_reg_write(rmi4_data,
- address,
- (unsigned char *)buf,
- length);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write data\n",
- __func__);
- return retval;
- }
- } else {
- return -EINVAL;
- }
-
- return length;
-}
-
-static ssize_t rmidev_sysfs_open_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- if (input != 1)
- return -EINVAL;
-
- if (rmi4_data->sensor_sleep) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Sensor sleeping\n",
- __func__);
- return -ENODEV;
- }
-
- rmi4_data->stay_awake = true;
-
- rmi4_data->irq_enable(rmi4_data, false, false);
- rmidev_sysfs_irq_enable(rmi4_data, true);
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Attention interrupt disabled\n",
- __func__);
-
- return count;
-}
-
-static ssize_t rmidev_sysfs_release_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- if (input != 1)
- return -EINVAL;
-
- rmidev_sysfs_irq_enable(rmi4_data, false);
- rmi4_data->irq_enable(rmi4_data, true, false);
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Attention interrupt enabled\n",
- __func__);
-
- rmi4_data->reset_device(rmi4_data, false);
-
- rmi4_data->stay_awake = false;
-
- return count;
-}
-
-static ssize_t rmidev_sysfs_attn_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int attn_state;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- attn_state = gpio_get_value(bdata->irq_gpio);
-
- return snprintf(buf, PAGE_SIZE, "%u\n", attn_state);
-}
-
-static ssize_t rmidev_sysfs_pid_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", rmidev->pid);
-}
-
-static ssize_t rmidev_sysfs_pid_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- unsigned int input;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- rmidev->pid = input;
-
- if (rmidev->pid) {
- rmidev->task = pid_task(find_vpid(rmidev->pid), PIDTYPE_PID);
- if (!rmidev->task) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to locate PID of data logging tool\n",
- __func__);
- return -EINVAL;
- }
- }
-
- return count;
-}
-
-static ssize_t rmidev_sysfs_term_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- unsigned int input;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- if (input != 1)
- return -EINVAL;
-
- if (rmidev->pid)
- send_sig_info(SIGTERM, &rmidev->terminate_signal, rmidev->task);
-
- return count;
-}
-
-static ssize_t rmidev_sysfs_intr_mask_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "0x%02x\n", rmidev->intr_mask);
-}
-
-static ssize_t rmidev_sysfs_intr_mask_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- unsigned int input;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- rmidev->intr_mask = (unsigned char)input;
-
- return count;
-}
-
-static ssize_t rmidev_sysfs_concurrent_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%d\n", rmidev->concurrent);
-}
-
-static ssize_t rmidev_sysfs_concurrent_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- unsigned int input;
-
- if (sscanf(buf, "%u", &input) != 1)
- return -EINVAL;
-
- rmidev->concurrent = input > 0 ? true : false;
-
- return count;
-}
-
-static int rmidev_allocate_buffer(int count)
-{
- if (count + 1 > rmidev->tmpbuf_size) {
- if (rmidev->tmpbuf_size)
- kfree(rmidev->tmpbuf);
- rmidev->tmpbuf = kzalloc(count + 1, GFP_KERNEL);
- if (!rmidev->tmpbuf) {
- dev_err(rmidev->rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for buffer\n",
- __func__);
- rmidev->tmpbuf_size = 0;
- return -ENOMEM;
- }
- rmidev->tmpbuf_size = count + 1;
- }
-
- return 0;
-}
-
-/*
- * rmidev_llseek - set register address to access for RMI device
- *
- * @filp: pointer to file structure
- * @off:
- * if whence == SEEK_SET,
- * off: 16-bit RMI register address
- * if whence == SEEK_CUR,
- * off: offset from current position
- * if whence == SEEK_END,
- * off: offset from end position (0xFFFF)
- * @whence: SEEK_SET, SEEK_CUR, or SEEK_END
- */
-static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence)
-{
- loff_t newpos;
- struct rmidev_data *dev_data = filp->private_data;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- if (IS_ERR(dev_data)) {
- pr_err("%s: Pointer of char device data is invalid", __func__);
- return -EBADF;
- }
-
- mutex_lock(&(dev_data->file_mutex));
-
- switch (whence) {
- case SEEK_SET:
- newpos = off;
- break;
- case SEEK_CUR:
- newpos = filp->f_pos + off;
- break;
- case SEEK_END:
- newpos = REG_ADDR_LIMIT + off;
- break;
- default:
- newpos = -EINVAL;
- goto clean_up;
- }
-
- if (newpos < 0 || newpos > REG_ADDR_LIMIT) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: New position 0x%04x is invalid\n",
- __func__, (unsigned int)newpos);
- newpos = -EINVAL;
- goto clean_up;
- }
-
- filp->f_pos = newpos;
-
-clean_up:
- mutex_unlock(&(dev_data->file_mutex));
-
- return newpos;
-}
-
-/*
- * rmidev_read: read register data from RMI device
- *
- * @filp: pointer to file structure
- * @buf: pointer to user space buffer
- * @count: number of bytes to read
- * @f_pos: starting RMI register address
- */
-static ssize_t rmidev_read(struct file *filp, char __user *buf,
- size_t count, loff_t *f_pos)
-{
- ssize_t retval;
- unsigned char intr_status = 0;
- unsigned short address;
- struct rmidev_data *dev_data = filp->private_data;
- struct synaptics_rmi4_fn *fhandler;
- struct synaptics_rmi4_device_info *rmi;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- rmi = &(rmi4_data->rmi4_mod_info);
-
- if (IS_ERR(dev_data)) {
- pr_err("%s: Pointer of char device data is invalid", __func__);
- return -EBADF;
- }
-
- if (count == 0)
- return 0;
-
- if (count > (REG_ADDR_LIMIT - *f_pos))
- count = REG_ADDR_LIMIT - *f_pos;
-
- address = (unsigned short)(*f_pos);
-
- rmidev_allocate_buffer(count);
-
- mutex_lock(&(dev_data->file_mutex));
-
- retval = synaptics_rmi4_reg_read(rmidev->rmi4_data,
- *f_pos,
- rmidev->tmpbuf,
- count);
- if (retval < 0)
- goto clean_up;
-
- if (copy_to_user(buf, rmidev->tmpbuf, count))
- retval = -EFAULT;
- else
- *f_pos += retval;
-
- if (!rmidev->concurrent)
- goto clean_up;
-
- if (address != rmi4_data->f01_data_base_addr)
- goto clean_up;
-
- if (count <= 1)
- goto clean_up;
-
- intr_status = rmidev->tmpbuf[1];
-
- if (!list_empty(&rmi->support_fn_list)) {
- list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
- if (fhandler->num_of_data_sources) {
- if (fhandler->intr_mask & intr_status) {
- rmi4_data->report_touch(rmi4_data,
- fhandler);
- }
- }
- }
- }
-
-clean_up:
- mutex_unlock(&(dev_data->file_mutex));
-
- return retval;
-}
-
-/*
- * rmidev_write: write register data to RMI device
- *
- * @filp: pointer to file structure
- * @buf: pointer to user space buffer
- * @count: number of bytes to write
- * @f_pos: starting RMI register address
- */
-static ssize_t rmidev_write(struct file *filp, const char __user *buf,
- size_t count, loff_t *f_pos)
-{
- ssize_t retval;
- struct rmidev_data *dev_data = filp->private_data;
-
- if (IS_ERR(dev_data)) {
- pr_err("%s: Pointer of char device data is invalid", __func__);
- return -EBADF;
- }
-
- if (count == 0)
- return 0;
-
- if (count > (REG_ADDR_LIMIT - *f_pos))
- count = REG_ADDR_LIMIT - *f_pos;
-
- rmidev_allocate_buffer(count);
-
- if (copy_from_user(rmidev->tmpbuf, buf, count))
- return -EFAULT;
-
- mutex_lock(&(dev_data->file_mutex));
-
- retval = synaptics_rmi4_reg_write(rmidev->rmi4_data,
- *f_pos,
- rmidev->tmpbuf,
- count);
- if (retval >= 0)
- *f_pos += retval;
-
- mutex_unlock(&(dev_data->file_mutex));
-
- return retval;
-}
-
-static int rmidev_open(struct inode *inp, struct file *filp)
-{
- int retval = 0;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
- struct rmidev_data *dev_data =
- container_of(inp->i_cdev, struct rmidev_data, main_dev);
-
- if (!dev_data)
- return -EACCES;
-
- if (rmi4_data->sensor_sleep) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Sensor sleeping\n",
- __func__);
- return -ENODEV;
- }
-
- rmi4_data->stay_awake = true;
-
- filp->private_data = dev_data;
-
- mutex_lock(&(dev_data->file_mutex));
-
- rmi4_data->irq_enable(rmi4_data, false, false);
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Attention interrupt disabled\n",
- __func__);
-
- if (dev_data->ref_count < 1)
- dev_data->ref_count++;
- else
- retval = -EACCES;
-
- mutex_unlock(&(dev_data->file_mutex));
-
- return retval;
-}
-
-static int rmidev_release(struct inode *inp, struct file *filp)
-{
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
- struct rmidev_data *dev_data =
- container_of(inp->i_cdev, struct rmidev_data, main_dev);
-
- if (!dev_data)
- return -EACCES;
-
- mutex_lock(&(dev_data->file_mutex));
-
- dev_data->ref_count--;
- if (dev_data->ref_count < 0)
- dev_data->ref_count = 0;
-
- rmi4_data->irq_enable(rmi4_data, true, false);
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Attention interrupt enabled\n",
- __func__);
-
- mutex_unlock(&(dev_data->file_mutex));
-
- rmi4_data->reset_device(rmi4_data, false);
-
- rmi4_data->stay_awake = false;
-
- return 0;
-}
-
-static const struct file_operations rmidev_fops = {
- .owner = THIS_MODULE,
- .llseek = rmidev_llseek,
- .read = rmidev_read,
- .write = rmidev_write,
- .open = rmidev_open,
- .release = rmidev_release,
-};
-
-static void rmidev_device_cleanup(struct rmidev_data *dev_data)
-{
- dev_t devno;
- struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
-
- if (dev_data) {
- devno = dev_data->main_dev.dev;
-
- if (dev_data->device_class)
- device_destroy(dev_data->device_class, devno);
-
- cdev_del(&dev_data->main_dev);
-
- unregister_chrdev_region(devno, 1);
-
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: rmidev device removed\n",
- __func__);
- }
-
- return;
-}
-
-static char *rmi_char_devnode(struct device *dev, umode_t *mode)
-{
- if (!mode)
- return NULL;
-
- *mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
-
- return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev));
-}
-
-static int rmidev_create_device_class(void)
-{
- if (rmidev_device_class != NULL)
- return 0;
-
- rmidev_device_class = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
-
- if (IS_ERR(rmidev_device_class)) {
- pr_err("%s: Failed to create /dev/%s\n",
- __func__, CHAR_DEVICE_NAME);
- return -ENODEV;
- }
-
- rmidev_device_class->devnode = rmi_char_devnode;
-
- return 0;
-}
-
-static void rmidev_attn(struct synaptics_rmi4_data *rmi4_data,
- unsigned char intr_mask)
-{
- if (!rmidev)
- return;
-
- if (rmidev->pid && (rmidev->intr_mask & intr_mask))
- send_sig_info(SIGIO, &rmidev->interrupt_signal, rmidev->task);
-
- return;
-}
-
-static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- dev_t dev_no;
- unsigned char attr_count;
- struct rmidev_data *dev_data;
- struct device *device_ptr;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- if (rmidev) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Handle already exists\n",
- __func__);
- return 0;
- }
-
- rmidev = kzalloc(sizeof(*rmidev), GFP_KERNEL);
- if (!rmidev) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for rmidev\n",
- __func__);
- retval = -ENOMEM;
- goto err_rmidev;
- }
-
- rmidev->rmi4_data = rmi4_data;
-
- memset(&rmidev->interrupt_signal, 0, sizeof(rmidev->interrupt_signal));
- rmidev->interrupt_signal.si_signo = SIGIO;
- rmidev->interrupt_signal.si_code = SI_USER;
-
- memset(&rmidev->terminate_signal, 0, sizeof(rmidev->terminate_signal));
- rmidev->terminate_signal.si_signo = SIGTERM;
- rmidev->terminate_signal.si_code = SI_USER;
-
- retval = rmidev_create_device_class();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create device class\n",
- __func__);
- goto err_device_class;
- }
-
- if (rmidev_major_num) {
- dev_no = MKDEV(rmidev_major_num, DEV_NUMBER);
- retval = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME);
- } else {
- retval = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to allocate char device region\n",
- __func__);
- goto err_device_region;
- }
-
- rmidev_major_num = MAJOR(dev_no);
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Major number of rmidev = %d\n",
- __func__, rmidev_major_num);
- }
-
- dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL);
- if (!dev_data) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for dev_data\n",
- __func__);
- retval = -ENOMEM;
- goto err_dev_data;
- }
-
- mutex_init(&dev_data->file_mutex);
- dev_data->rmi_dev = rmidev;
- rmidev->data = dev_data;
-
- cdev_init(&dev_data->main_dev, &rmidev_fops);
-
- retval = cdev_add(&dev_data->main_dev, dev_no, 1);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to add rmi char device\n",
- __func__);
- goto err_char_device;
- }
-
- dev_set_name(&rmidev->dev, "rmidev%d", MINOR(dev_no));
- dev_data->device_class = rmidev_device_class;
-
- device_ptr = device_create(dev_data->device_class, NULL, dev_no,
- NULL, CHAR_DEVICE_NAME"%d", MINOR(dev_no));
- if (IS_ERR(device_ptr)) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create rmi char device\n",
- __func__);
- retval = -ENODEV;
- goto err_char_device;
- }
-
- retval = gpio_export(bdata->irq_gpio, false);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to export attention gpio\n",
- __func__);
- } else {
- retval = gpio_export_link(&(rmi4_data->input_dev->dev),
- "attn", bdata->irq_gpio);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s Failed to create gpio symlink\n",
- __func__);
- } else {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Exported attention gpio %d\n",
- __func__, bdata->irq_gpio);
- }
- }
-
- rmidev->sysfs_dir = kobject_create_and_add(SYSFS_FOLDER_NAME,
- &rmi4_data->input_dev->dev.kobj);
- if (!rmidev->sysfs_dir) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs directory\n",
- __func__);
- retval = -ENODEV;
- goto err_sysfs_dir;
- }
-
- retval = sysfs_create_bin_file(rmidev->sysfs_dir,
- &attr_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs bin file\n",
- __func__);
- goto err_sysfs_bin;
- }
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- retval = sysfs_create_file(rmidev->sysfs_dir,
- &attrs[attr_count].attr);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs attributes\n",
- __func__);
- retval = -ENODEV;
- goto err_sysfs_attrs;
- }
- }
-
- return 0;
-
-err_sysfs_attrs:
- for (attr_count--; attr_count >= 0; attr_count--)
- sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr);
-
- sysfs_remove_bin_file(rmidev->sysfs_dir, &attr_data);
-
-err_sysfs_bin:
- kobject_put(rmidev->sysfs_dir);
-
-err_sysfs_dir:
-err_char_device:
- rmidev_device_cleanup(dev_data);
- kfree(dev_data);
-
-err_dev_data:
- unregister_chrdev_region(dev_no, 1);
-
-err_device_region:
- if (rmidev_device_class != NULL) {
- class_destroy(rmidev_device_class);
- rmidev_device_class = NULL;
- }
-
-err_device_class:
- kfree(rmidev);
- rmidev = NULL;
-
-err_rmidev:
- return retval;
-}
-
-static void rmidev_remove_device(struct synaptics_rmi4_data *rmi4_data)
-{
- unsigned char attr_count;
- struct rmidev_data *dev_data;
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- if (!rmidev)
- goto exit;
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++)
- sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr);
-
- sysfs_remove_bin_file(rmidev->sysfs_dir, &attr_data);
-
- kobject_put(rmidev->sysfs_dir);
-
- gpio_unexport(bdata->irq_gpio);
-
- dev_data = rmidev->data;
- if (dev_data) {
- rmidev_device_cleanup(dev_data);
- kfree(dev_data);
- }
-
- unregister_chrdev_region(rmidev->dev_no, 1);
-
- if (rmidev_device_class != NULL) {
- class_destroy(rmidev_device_class);
- rmidev_device_class = NULL;
- }
-
- kfree(rmidev->tmpbuf);
-
- kfree(rmidev);
- rmidev = NULL;
-
-exit:
- complete(&rmidev_remove_complete_v26);
-
- return;
-}
-
-static struct synaptics_rmi4_exp_fn rmidev_module = {
- .fn_type = RMI_DEV,
- .init = rmidev_init_device,
- .remove = rmidev_remove_device,
- .reset = NULL,
- .reinit = NULL,
- .early_suspend = NULL,
- .suspend = NULL,
- .resume = NULL,
- .late_resume = NULL,
- .attn = rmidev_attn,
-};
-
-static int __init rmidev_module_init(void)
-{
- synaptics_rmi4_new_function(&rmidev_module, true);
-
- return 0;
-}
-
-static void __exit rmidev_module_exit(void)
-{
- synaptics_rmi4_new_function(&rmidev_module, false);
-
- wait_for_completion(&rmidev_remove_complete_v26);
-
- return;
-}
-
-module_init(rmidev_module_init);
-module_exit(rmidev_module_exit);
-
-MODULE_AUTHOR("Synaptics, Inc.");
-MODULE_DESCRIPTION("Synaptics DSX RMI Dev Module");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_hid_i2c.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_hid_i2c.c
deleted file mode 100644
index 7e02487ece5a..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_rmi_hid_i2c.c
+++ /dev/null
@@ -1,1006 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/gpio.h>
-#include <linux/types.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx_v2_6.h>
-#include "synaptics_dsx_core.h"
-
-#define SYN_I2C_RETRY_TIMES 10
-
-#define REPORT_ID_GET_BLOB 0x07
-#define REPORT_ID_WRITE 0x09
-#define REPORT_ID_READ_ADDRESS 0x0a
-#define REPORT_ID_READ_DATA 0x0b
-#define REPORT_ID_SET_RMI_MODE 0x0f
-
-#define PREFIX_USAGE_PAGE_1BYTE 0x05
-#define PREFIX_USAGE_PAGE_2BYTES 0x06
-#define PREFIX_USAGE 0x09
-#define PREFIX_REPORT_ID 0x85
-#define PREFIX_REPORT_COUNT_1BYTE 0x95
-#define PREFIX_REPORT_COUNT_2BYTES 0x96
-
-#define USAGE_GET_BLOB 0xc5
-#define USAGE_WRITE 0x02
-#define USAGE_READ_ADDRESS 0x03
-#define USAGE_READ_DATA 0x04
-#define USAGE_SET_MODE 0x06
-
-#define FEATURE_REPORT_TYPE 0x03
-
-#define VENDOR_DEFINED_PAGE 0xff00
-
-#define BLOB_REPORT_SIZE 256
-
-#define RESET_COMMAND 0x01
-#define GET_REPORT_COMMAND 0x02
-#define SET_REPORT_COMMAND 0x03
-#define SET_POWER_COMMAND 0x08
-
-#define FINGER_MODE 0x00
-#define RMI_MODE 0x02
-
-struct hid_report_info {
- unsigned char get_blob_id;
- unsigned char write_id;
- unsigned char read_addr_id;
- unsigned char read_data_id;
- unsigned char set_mode_id;
- unsigned int blob_size;
-};
-
-static struct hid_report_info hid_report;
-
-struct hid_device_descriptor {
- unsigned short device_descriptor_length;
- unsigned short format_version;
- unsigned short report_descriptor_length;
- unsigned short report_descriptor_index;
- unsigned short input_register_index;
- unsigned short input_report_max_length;
- unsigned short output_register_index;
- unsigned short output_report_max_length;
- unsigned short command_register_index;
- unsigned short data_register_index;
- unsigned short vendor_id;
- unsigned short product_id;
- unsigned short version_id;
- unsigned int reserved;
-};
-
-static struct hid_device_descriptor hid_dd;
-
-struct i2c_rw_buffer {
- unsigned char *read;
- unsigned char *write;
- unsigned short read_size;
- unsigned short write_size;
-};
-
-static struct i2c_rw_buffer buffer;
-
-#ifdef CONFIG_OF
-static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
-{
- int retval;
- u32 value;
- const char *name;
- struct property *prop;
- struct device_node *np = dev->of_node;
-
- bdata->irq_gpio = of_get_named_gpio_flags(np,
- "synaptics,irq-gpio", 0,
- (enum of_gpio_flags *)&bdata->irq_flags);
-
- retval = of_property_read_u32(np, "synaptics,irq-on-state",
- &value);
- if (retval < 0)
- bdata->irq_on_state = 0;
- else
- bdata->irq_on_state = value;
-
- retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
- if (retval < 0)
- bdata->pwr_reg_name = NULL;
- else
- bdata->pwr_reg_name = name;
-
- retval = of_property_read_string(np, "synaptics,bus-reg-name", &name);
- if (retval < 0)
- bdata->bus_reg_name = NULL;
- else
- bdata->bus_reg_name = name;
-
- prop = of_find_property(np, "synaptics,power-gpio", NULL);
- if (prop && prop->length) {
- bdata->power_gpio = of_get_named_gpio_flags(np,
- "synaptics,power-gpio", 0, NULL);
- retval = of_property_read_u32(np, "synaptics,power-on-state",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,power-on-state property\n",
- __func__);
- return retval;
- } else {
- bdata->power_on_state = value;
- }
- } else {
- bdata->power_gpio = -1;
- }
-
- prop = of_find_property(np, "synaptics,power-delay-ms", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,power-delay-ms",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,power-delay-ms property\n",
- __func__);
- return retval;
- } else {
- bdata->power_delay_ms = value;
- }
- } else {
- bdata->power_delay_ms = 0;
- }
-
- prop = of_find_property(np, "synaptics,reset-gpio", NULL);
- if (prop && prop->length) {
- bdata->reset_gpio = of_get_named_gpio_flags(np,
- "synaptics,reset-gpio", 0, NULL);
- retval = of_property_read_u32(np, "synaptics,reset-on-state",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,reset-on-state property\n",
- __func__);
- return retval;
- } else {
- bdata->reset_on_state = value;
- }
- retval = of_property_read_u32(np, "synaptics,reset-active-ms",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,reset-active-ms property\n",
- __func__);
- return retval;
- } else {
- bdata->reset_active_ms = value;
- }
- } else {
- bdata->reset_gpio = -1;
- }
-
- prop = of_find_property(np, "synaptics,reset-delay-ms", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,reset-delay-ms",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,reset-delay-ms property\n",
- __func__);
- return retval;
- } else {
- bdata->reset_delay_ms = value;
- }
- } else {
- bdata->reset_delay_ms = 0;
- }
-
- prop = of_find_property(np, "synaptics,dev-dscrptr-addr", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,dev-dscrptr-addr",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,dev-dscrptr-addr property\n",
- __func__);
- return retval;
- } else {
- bdata->device_descriptor_addr = (unsigned short)value;
- }
- } else {
- bdata->device_descriptor_addr = 0;
- }
-
- prop = of_find_property(np, "synaptics,max-y-for-2d", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,max-y-for-2d",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,max-y-for-2d property\n",
- __func__);
- return retval;
- } else {
- bdata->max_y_for_2d = value;
- }
- } else {
- bdata->max_y_for_2d = -1;
- }
-
- prop = of_find_property(np, "synaptics,swap-axes", NULL);
- bdata->swap_axes = prop > 0 ? true : false;
-
- prop = of_find_property(np, "synaptics,x-flip", NULL);
- bdata->x_flip = prop > 0 ? true : false;
-
- prop = of_find_property(np, "synaptics,y-flip", NULL);
- bdata->y_flip = prop > 0 ? true : false;
-
- prop = of_find_property(np, "synaptics,ub-i2c-addr", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,ub-i2c-addr",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,ub-i2c-addr property\n",
- __func__);
- return retval;
- } else {
- bdata->ub_i2c_addr = (unsigned short)value;
- }
- } else {
- bdata->ub_i2c_addr = -1;
- }
-
- prop = of_find_property(np, "synaptics,cap-button-codes", NULL);
- if (prop && prop->length) {
- bdata->cap_button_map->map = devm_kzalloc(dev,
- prop->length,
- GFP_KERNEL);
- if (!bdata->cap_button_map->map)
- return -ENOMEM;
- bdata->cap_button_map->nbuttons = prop->length / sizeof(u32);
- retval = of_property_read_u32_array(np,
- "synaptics,cap-button-codes",
- bdata->cap_button_map->map,
- bdata->cap_button_map->nbuttons);
- if (retval < 0) {
- bdata->cap_button_map->nbuttons = 0;
- bdata->cap_button_map->map = NULL;
- }
- } else {
- bdata->cap_button_map->nbuttons = 0;
- bdata->cap_button_map->map = NULL;
- }
-
- prop = of_find_property(np, "synaptics,vir-button-codes", NULL);
- if (prop && prop->length) {
- bdata->vir_button_map->map = devm_kzalloc(dev,
- prop->length,
- GFP_KERNEL);
- if (!bdata->vir_button_map->map)
- return -ENOMEM;
- bdata->vir_button_map->nbuttons = prop->length / sizeof(u32);
- bdata->vir_button_map->nbuttons /= 5;
- retval = of_property_read_u32_array(np,
- "synaptics,vir-button-codes",
- bdata->vir_button_map->map,
- bdata->vir_button_map->nbuttons * 5);
- if (retval < 0) {
- bdata->vir_button_map->nbuttons = 0;
- bdata->vir_button_map->map = NULL;
- }
- } else {
- bdata->vir_button_map->nbuttons = 0;
- bdata->vir_button_map->map = NULL;
- }
-
- return 0;
-}
-#endif
-
-static int do_i2c_transfer(struct i2c_client *client, struct i2c_msg *msg)
-{
- unsigned char retry;
-
- for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
- if (i2c_transfer(client->adapter, msg, 1) == 1)
- break;
- dev_err(&client->dev,
- "%s: I2C retry %d\n",
- __func__, retry + 1);
- msleep(20);
- }
-
- if (retry == SYN_I2C_RETRY_TIMES) {
- dev_err(&client->dev,
- "%s: I2C transfer over retry limit\n",
- __func__);
- return -EIO;
- }
-
- return 0;
-}
-
-static int check_buffer(unsigned char **buffer, unsigned short *buffer_size,
- unsigned short length)
-{
- if (*buffer_size < length) {
- if (*buffer_size)
- kfree(*buffer);
- *buffer = kzalloc(length, GFP_KERNEL);
- if (!(*buffer))
- return -ENOMEM;
- *buffer_size = length;
- }
-
- return 0;
-}
-
-static int generic_read(struct i2c_client *client, unsigned short length)
-{
- int retval;
- struct i2c_msg msg[] = {
- {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = length,
- }
- };
-
- check_buffer(&buffer.read, &buffer.read_size, length);
- msg[0].buf = buffer.read;
-
- retval = do_i2c_transfer(client, msg);
-
- return retval;
-}
-
-static int generic_write(struct i2c_client *client, unsigned short length)
-{
- int retval;
- struct i2c_msg msg[] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = length,
- .buf = buffer.write,
- }
- };
-
- retval = do_i2c_transfer(client, msg);
-
- return retval;
-}
-
-static void traverse_report_descriptor(unsigned int *index)
-{
- unsigned char size;
- unsigned char *buf = buffer.read;
-
- size = buf[*index] & MASK_2BIT;
- switch (size) {
- case 0: /* 0 bytes */
- *index += 1;
- break;
- case 1: /* 1 byte */
- *index += 2;
- break;
- case 2: /* 2 bytes */
- *index += 3;
- break;
- case 3: /* 4 bytes */
- *index += 5;
- break;
- default:
- break;
- }
-
- return;
-}
-
-static void find_blob_size(unsigned int index)
-{
- unsigned int ii = index;
- unsigned char *buf = buffer.read;
-
- while (ii < hid_dd.report_descriptor_length) {
- if (buf[ii] == PREFIX_REPORT_COUNT_1BYTE) {
- hid_report.blob_size = buf[ii + 1];
- return;
- } else if (buf[ii] == PREFIX_REPORT_COUNT_2BYTES) {
- hid_report.blob_size = buf[ii + 1] | (buf[ii + 2] << 8);
- return;
- }
- traverse_report_descriptor(&ii);
- }
-
- return;
-}
-
-static void find_reports(unsigned int index)
-{
- unsigned int ii = index;
- unsigned char *buf = buffer.read;
- static unsigned int report_id_index;
- static unsigned char report_id;
- static unsigned short usage_page;
-
- if (buf[ii] == PREFIX_REPORT_ID) {
- report_id = buf[ii + 1];
- report_id_index = ii;
- return;
- }
-
- if (buf[ii] == PREFIX_USAGE_PAGE_1BYTE) {
- usage_page = buf[ii + 1];
- return;
- } else if (buf[ii] == PREFIX_USAGE_PAGE_2BYTES) {
- usage_page = buf[ii + 1] | (buf[ii + 2] << 8);
- return;
- }
-
- if ((usage_page == VENDOR_DEFINED_PAGE) && (buf[ii] == PREFIX_USAGE)) {
- switch (buf[ii + 1]) {
- case USAGE_GET_BLOB:
- hid_report.get_blob_id = report_id;
- find_blob_size(report_id_index);
- break;
- case USAGE_WRITE:
- hid_report.write_id = report_id;
- break;
- case USAGE_READ_ADDRESS:
- hid_report.read_addr_id = report_id;
- break;
- case USAGE_READ_DATA:
- hid_report.read_data_id = report_id;
- break;
- case USAGE_SET_MODE:
- hid_report.set_mode_id = report_id;
- break;
- default:
- break;
- }
- }
-
- return;
-}
-
-static int parse_report_descriptor(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- unsigned int ii = 0;
- unsigned char *buf;
- struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
-
- buffer.write[0] = hid_dd.report_descriptor_index & MASK_8BIT;
- buffer.write[1] = hid_dd.report_descriptor_index >> 8;
- retval = generic_write(i2c, 2);
- if (retval < 0)
- return retval;
- retval = generic_read(i2c, hid_dd.report_descriptor_length);
- if (retval < 0)
- return retval;
-
- buf = buffer.read;
-
- hid_report.get_blob_id = REPORT_ID_GET_BLOB;
- hid_report.write_id = REPORT_ID_WRITE;
- hid_report.read_addr_id = REPORT_ID_READ_ADDRESS;
- hid_report.read_data_id = REPORT_ID_READ_DATA;
- hid_report.set_mode_id = REPORT_ID_SET_RMI_MODE;
- hid_report.blob_size = BLOB_REPORT_SIZE;
-
- while (ii < hid_dd.report_descriptor_length) {
- find_reports(ii);
- traverse_report_descriptor(&ii);
- }
-
- return 0;
-}
-
-static int switch_to_rmi(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
-
- mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- check_buffer(&buffer.write, &buffer.write_size, 11);
-
- /* set rmi mode */
- buffer.write[0] = hid_dd.command_register_index & MASK_8BIT;
- buffer.write[1] = hid_dd.command_register_index >> 8;
- buffer.write[2] = (FEATURE_REPORT_TYPE << 4) | hid_report.set_mode_id;
- buffer.write[3] = SET_REPORT_COMMAND;
- buffer.write[4] = hid_report.set_mode_id;
- buffer.write[5] = hid_dd.data_register_index & MASK_8BIT;
- buffer.write[6] = hid_dd.data_register_index >> 8;
- buffer.write[7] = 0x04;
- buffer.write[8] = 0x00;
- buffer.write[9] = hid_report.set_mode_id;
- buffer.write[10] = RMI_MODE;
-
- retval = generic_write(i2c, 11);
-
- mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- return retval;
-}
-
-static int check_report_mode(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- unsigned short report_size;
- struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
-
- mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- check_buffer(&buffer.write, &buffer.write_size, 7);
-
- buffer.write[0] = hid_dd.command_register_index & MASK_8BIT;
- buffer.write[1] = hid_dd.command_register_index >> 8;
- buffer.write[2] = (FEATURE_REPORT_TYPE << 4) | hid_report.set_mode_id;
- buffer.write[3] = GET_REPORT_COMMAND;
- buffer.write[4] = hid_report.set_mode_id;
- buffer.write[5] = hid_dd.data_register_index & MASK_8BIT;
- buffer.write[6] = hid_dd.data_register_index >> 8;
-
- retval = generic_write(i2c, 7);
- if (retval < 0)
- goto exit;
-
- retval = generic_read(i2c, 2);
- if (retval < 0)
- goto exit;
-
- report_size = (buffer.read[1] << 8) | buffer.read[0];
-
- retval = generic_write(i2c, 7);
- if (retval < 0)
- goto exit;
-
- retval = generic_read(i2c, report_size);
- if (retval < 0)
- goto exit;
-
- retval = buffer.read[3];
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Report mode = %d\n",
- __func__, retval);
-
-exit:
- mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- return retval;
-}
-
-static int hid_i2c_init(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- check_buffer(&buffer.write, &buffer.write_size, 6);
-
- /* read device descriptor */
- buffer.write[0] = bdata->device_descriptor_addr & MASK_8BIT;
- buffer.write[1] = bdata->device_descriptor_addr >> 8;
- retval = generic_write(i2c, 2);
- if (retval < 0)
- goto exit;
- retval = generic_read(i2c, sizeof(hid_dd));
- if (retval < 0)
- goto exit;
- retval = secure_memcpy((unsigned char *)&hid_dd,
- sizeof(struct hid_device_descriptor),
- buffer.read,
- buffer.read_size,
- sizeof(hid_dd));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy device descriptor data\n",
- __func__);
- goto exit;
- }
-
- retval = parse_report_descriptor(rmi4_data);
- if (retval < 0)
- goto exit;
-
- /* set power */
- buffer.write[0] = hid_dd.command_register_index & MASK_8BIT;
- buffer.write[1] = hid_dd.command_register_index >> 8;
- buffer.write[2] = 0x00;
- buffer.write[3] = SET_POWER_COMMAND;
- retval = generic_write(i2c, 4);
- if (retval < 0)
- goto exit;
-
- /* reset */
- buffer.write[0] = hid_dd.command_register_index & MASK_8BIT;
- buffer.write[1] = hid_dd.command_register_index >> 8;
- buffer.write[2] = 0x00;
- buffer.write[3] = RESET_COMMAND;
- retval = generic_write(i2c, 4);
- if (retval < 0)
- goto exit;
-
- while (gpio_get_value(bdata->irq_gpio))
- msleep(20);
-
- retval = generic_read(i2c, hid_dd.input_report_max_length);
- if (retval < 0)
- goto exit;
-
- /* get blob */
- buffer.write[0] = hid_dd.command_register_index & MASK_8BIT;
- buffer.write[1] = hid_dd.command_register_index >> 8;
- buffer.write[2] = (FEATURE_REPORT_TYPE << 4) | hid_report.get_blob_id;
- buffer.write[3] = 0x02;
- buffer.write[4] = hid_dd.data_register_index & MASK_8BIT;
- buffer.write[5] = hid_dd.data_register_index >> 8;
-
- retval = generic_write(i2c, 6);
- if (retval < 0)
- goto exit;
-
- msleep(20);
-
- retval = generic_read(i2c, hid_report.blob_size + 3);
- if (retval < 0)
- goto exit;
-
-exit:
- mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to initialize HID/I2C interface\n",
- __func__);
- return retval;
- }
-
- retval = switch_to_rmi(rmi4_data);
-
- return retval;
-}
-
-static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
- unsigned short addr, unsigned char *data, unsigned short length)
-{
- int retval;
- unsigned char retry;
- unsigned char recover = 1;
- unsigned short report_length;
- struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
- struct i2c_msg msg[] = {
- {
- .addr = i2c->addr,
- .flags = 0,
- .len = hid_dd.output_report_max_length + 2,
- },
- {
- .addr = i2c->addr,
- .flags = I2C_M_RD,
- .len = length + 4,
- },
- };
-
-recover:
- mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- check_buffer(&buffer.write, &buffer.write_size,
- hid_dd.output_report_max_length + 2);
- msg[0].buf = buffer.write;
- buffer.write[0] = hid_dd.output_register_index & MASK_8BIT;
- buffer.write[1] = hid_dd.output_register_index >> 8;
- buffer.write[2] = hid_dd.output_report_max_length & MASK_8BIT;
- buffer.write[3] = hid_dd.output_report_max_length >> 8;
- buffer.write[4] = hid_report.read_addr_id;
- buffer.write[5] = 0x00;
- buffer.write[6] = addr & MASK_8BIT;
- buffer.write[7] = addr >> 8;
- buffer.write[8] = length & MASK_8BIT;
- buffer.write[9] = length >> 8;
-
- check_buffer(&buffer.read, &buffer.read_size, length + 4);
- msg[1].buf = buffer.read;
-
- retval = do_i2c_transfer(i2c, &msg[0]);
- if (retval != 0)
- goto exit;
-
- retry = 0;
- do {
- retval = do_i2c_transfer(i2c, &msg[1]);
- if (retval == 0)
- retval = length;
- else
- goto exit;
-
- report_length = (buffer.read[1] << 8) | buffer.read[0];
- if (report_length == hid_dd.input_report_max_length) {
- retval = secure_memcpy(&data[0], length,
- &buffer.read[4], buffer.read_size - 4,
- length);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy data\n",
- __func__);
- } else {
- retval = length;
- }
- goto exit;
- }
-
- msleep(20);
- retry++;
- } while (retry < SYN_I2C_RETRY_TIMES);
-
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to receive read report\n",
- __func__);
- retval = -EIO;
-
-exit:
- mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- if ((retval != length) && (recover == 1)) {
- recover = 0;
- if (check_report_mode(rmi4_data) != RMI_MODE) {
- retval = hid_i2c_init(rmi4_data);
- if (retval == 0)
- goto recover;
- }
- }
-
- return retval;
-}
-
-static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
- unsigned short addr, unsigned char *data, unsigned short length)
-{
- int retval;
- unsigned char recover = 1;
- unsigned char msg_length;
- struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
- struct i2c_msg msg[] = {
- {
- .addr = i2c->addr,
- .flags = 0,
- }
- };
-
- if ((length + 10) < (hid_dd.output_report_max_length + 2))
- msg_length = hid_dd.output_report_max_length + 2;
- else
- msg_length = length + 10;
-
-recover:
- mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- check_buffer(&buffer.write, &buffer.write_size, msg_length);
- msg[0].len = msg_length;
- msg[0].buf = buffer.write;
- buffer.write[0] = hid_dd.output_register_index & MASK_8BIT;
- buffer.write[1] = hid_dd.output_register_index >> 8;
- buffer.write[2] = hid_dd.output_report_max_length & MASK_8BIT;
- buffer.write[3] = hid_dd.output_report_max_length >> 8;
- buffer.write[4] = hid_report.write_id;
- buffer.write[5] = 0x00;
- buffer.write[6] = addr & MASK_8BIT;
- buffer.write[7] = addr >> 8;
- buffer.write[8] = length & MASK_8BIT;
- buffer.write[9] = length >> 8;
- retval = secure_memcpy(&buffer.write[10], buffer.write_size - 10,
- &data[0], length, length);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy data\n",
- __func__);
- } else {
- retval = do_i2c_transfer(i2c, msg);
- if (retval == 0)
- retval = length;
- }
-
- mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- if ((retval != length) && (recover == 1)) {
- recover = 0;
- if (check_report_mode(rmi4_data) != RMI_MODE) {
- retval = hid_i2c_init(rmi4_data);
- if (retval == 0)
- goto recover;
- }
- }
-
- return retval;
-}
-
-static struct synaptics_dsx_bus_access bus_access = {
- .type = BUS_I2C,
- .read = synaptics_rmi4_i2c_read,
- .write = synaptics_rmi4_i2c_write,
-};
-
-static struct synaptics_dsx_hw_interface hw_if;
-
-static struct platform_device *synaptics_dsx_i2c_device;
-
-static void synaptics_rmi4_i2c_dev_release(struct device *dev)
-{
- kfree(synaptics_dsx_i2c_device);
-
- return;
-}
-
-static int synaptics_rmi4_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *dev_id)
-{
- int retval;
-
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA)) {
- dev_err(&client->dev,
- "%s: SMBus byte data commands not supported by host\n",
- __func__);
- return -EIO;
- }
-
- synaptics_dsx_i2c_device = kzalloc(
- sizeof(struct platform_device),
- GFP_KERNEL);
- if (!synaptics_dsx_i2c_device) {
- dev_err(&client->dev,
- "%s: Failed to allocate memory for synaptics_dsx_i2c_device\n",
- __func__);
- return -ENOMEM;
- }
-
-#ifdef CONFIG_OF
- if (client->dev.of_node) {
- hw_if.board_data = devm_kzalloc(&client->dev,
- sizeof(struct synaptics_dsx_board_data),
- GFP_KERNEL);
- if (!hw_if.board_data) {
- dev_err(&client->dev,
- "%s: Failed to allocate memory for board data\n",
- __func__);
- return -ENOMEM;
- }
- hw_if.board_data->cap_button_map = devm_kzalloc(&client->dev,
- sizeof(struct synaptics_dsx_button_map),
- GFP_KERNEL);
- if (!hw_if.board_data->cap_button_map) {
- dev_err(&client->dev,
- "%s: Failed to allocate memory for 0D button map\n",
- __func__);
- return -ENOMEM;
- }
- hw_if.board_data->vir_button_map = devm_kzalloc(&client->dev,
- sizeof(struct synaptics_dsx_button_map),
- GFP_KERNEL);
- if (!hw_if.board_data->vir_button_map) {
- dev_err(&client->dev,
- "%s: Failed to allocate memory for virtual button map\n",
- __func__);
- return -ENOMEM;
- }
- parse_dt(&client->dev, hw_if.board_data);
- }
-#else
- hw_if.board_data = client->dev.platform_data;
-#endif
-
- hw_if.bus_access = &bus_access;
- hw_if.bl_hw_init = switch_to_rmi;
- hw_if.ui_hw_init = hid_i2c_init;
-
- synaptics_dsx_i2c_device->name = PLATFORM_DRIVER_NAME;
- synaptics_dsx_i2c_device->id = 0;
- synaptics_dsx_i2c_device->num_resources = 0;
- synaptics_dsx_i2c_device->dev.parent = &client->dev;
- synaptics_dsx_i2c_device->dev.platform_data = &hw_if;
- synaptics_dsx_i2c_device->dev.release = synaptics_rmi4_i2c_dev_release;
-
- retval = platform_device_register(synaptics_dsx_i2c_device);
- if (retval) {
- dev_err(&client->dev,
- "%s: Failed to register platform device\n",
- __func__);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int synaptics_rmi4_i2c_remove(struct i2c_client *client)
-{
- if (buffer.read_size)
- kfree(buffer.read);
-
- if (buffer.write_size)
- kfree(buffer.write);
-
- platform_device_unregister(synaptics_dsx_i2c_device);
-
- return 0;
-}
-
-static const struct i2c_device_id synaptics_rmi4_id_table[] = {
- {I2C_DRIVER_NAME, 0},
- {},
-};
-MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
-
-#ifdef CONFIG_OF
-static struct of_device_id synaptics_rmi4_of_match_table[] = {
- {
- .compatible = "synaptics,dsx-rmi-hid-i2c",
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, synaptics_rmi4_of_match_table);
-#else
-#define synaptics_rmi4_of_match_table NULL
-#endif
-
-static struct i2c_driver synaptics_rmi4_i2c_driver = {
- .driver = {
- .name = I2C_DRIVER_NAME,
- .owner = THIS_MODULE,
- .of_match_table = synaptics_rmi4_of_match_table,
- },
- .probe = synaptics_rmi4_i2c_probe,
- .remove = synaptics_rmi4_i2c_remove,
- .id_table = synaptics_rmi4_id_table,
-};
-
-int synaptics_rmi4_bus_init_v26(void)
-{
- return i2c_add_driver(&synaptics_rmi4_i2c_driver);
-}
-EXPORT_SYMBOL(synaptics_rmi4_bus_init_v26);
-
-void synaptics_rmi4_bus_exit_v26(void)
-{
- i2c_del_driver(&synaptics_rmi4_i2c_driver);
-
- return;
-}
-EXPORT_SYMBOL(synaptics_rmi4_bus_exit_v26);
-
-MODULE_AUTHOR("Synaptics, Inc.");
-MODULE_DESCRIPTION("Synaptics DSX I2C Bus Support Module");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_spi.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_spi.c
deleted file mode 100644
index 382a3dd029d7..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_spi.c
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/spi/spi.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/types.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx_v2_6.h>
-#include "synaptics_dsx_core.h"
-
-#define SPI_READ 0x80
-#define SPI_WRITE 0x00
-
-#ifdef CONFIG_OF
-static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
-{
- int retval;
- u32 value;
- const char *name;
- struct property *prop;
- struct device_node *np = dev->of_node;
-
- bdata->irq_gpio = of_get_named_gpio_flags(np,
- "synaptics,irq-gpio", 0,
- (enum of_gpio_flags *)&bdata->irq_flags);
-
- retval = of_property_read_u32(np, "synaptics,irq-on-state",
- &value);
- if (retval < 0)
- bdata->irq_on_state = 0;
- else
- bdata->irq_on_state = value;
-
- retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
- if (retval < 0)
- bdata->pwr_reg_name = NULL;
- else
- bdata->pwr_reg_name = name;
-
- retval = of_property_read_string(np, "synaptics,bus-reg-name", &name);
- if (retval < 0)
- bdata->bus_reg_name = NULL;
- else
- bdata->bus_reg_name = name;
-
- prop = of_find_property(np, "synaptics,power-gpio", NULL);
- if (prop && prop->length) {
- bdata->power_gpio = of_get_named_gpio_flags(np,
- "synaptics,power-gpio", 0, NULL);
- retval = of_property_read_u32(np, "synaptics,power-on-state",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,power-on-state property\n",
- __func__);
- return retval;
- } else {
- bdata->power_on_state = value;
- }
- } else {
- bdata->power_gpio = -1;
- }
-
- prop = of_find_property(np, "synaptics,power-delay-ms", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,power-delay-ms",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,power-delay-ms property\n",
- __func__);
- return retval;
- } else {
- bdata->power_delay_ms = value;
- }
- } else {
- bdata->power_delay_ms = 0;
- }
-
- prop = of_find_property(np, "synaptics,reset-gpio", NULL);
- if (prop && prop->length) {
- bdata->reset_gpio = of_get_named_gpio_flags(np,
- "synaptics,reset-gpio", 0, NULL);
- retval = of_property_read_u32(np, "synaptics,reset-on-state",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,reset-on-state property\n",
- __func__);
- return retval;
- } else {
- bdata->reset_on_state = value;
- }
- retval = of_property_read_u32(np, "synaptics,reset-active-ms",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,reset-active-ms property\n",
- __func__);
- return retval;
- } else {
- bdata->reset_active_ms = value;
- }
- } else {
- bdata->reset_gpio = -1;
- }
-
- prop = of_find_property(np, "synaptics,reset-delay-ms", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,reset-delay-ms",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,reset-delay-ms property\n",
- __func__);
- return retval;
- } else {
- bdata->reset_delay_ms = value;
- }
- } else {
- bdata->reset_delay_ms = 0;
- }
-
- prop = of_find_property(np, "synaptics,byte-delay-us", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,byte-delay-us",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,byte-delay-us property\n",
- __func__);
- return retval;
- } else {
- bdata->byte_delay_us = value;
- }
- } else {
- bdata->byte_delay_us = 0;
- }
-
- prop = of_find_property(np, "synaptics,block-delay-us", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,block-delay-us",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,block-delay-us property\n",
- __func__);
- return retval;
- } else {
- bdata->block_delay_us = value;
- }
- } else {
- bdata->block_delay_us = 0;
- }
-
- prop = of_find_property(np, "synaptics,max-y-for-2d", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,max-y-for-2d",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,max-y-for-2d property\n",
- __func__);
- return retval;
- } else {
- bdata->max_y_for_2d = value;
- }
- } else {
- bdata->max_y_for_2d = -1;
- }
-
- prop = of_find_property(np, "synaptics,swap-axes", NULL);
- bdata->swap_axes = prop > 0 ? true : false;
-
- prop = of_find_property(np, "synaptics,x-flip", NULL);
- bdata->x_flip = prop > 0 ? true : false;
-
- prop = of_find_property(np, "synaptics,y-flip", NULL);
- bdata->y_flip = prop > 0 ? true : false;
-
- prop = of_find_property(np, "synaptics,ub-i2c-addr", NULL);
- if (prop && prop->length) {
- retval = of_property_read_u32(np, "synaptics,ub-i2c-addr",
- &value);
- if (retval < 0) {
- dev_err(dev, "%s: Unable to read synaptics,ub-i2c-addr property\n",
- __func__);
- return retval;
- } else {
- bdata->ub_i2c_addr = (unsigned short)value;
- }
- } else {
- bdata->ub_i2c_addr = -1;
- }
-
- prop = of_find_property(np, "synaptics,cap-button-codes", NULL);
- if (prop && prop->length) {
- bdata->cap_button_map->map = devm_kzalloc(dev,
- prop->length,
- GFP_KERNEL);
- if (!bdata->cap_button_map->map)
- return -ENOMEM;
- bdata->cap_button_map->nbuttons = prop->length / sizeof(u32);
- retval = of_property_read_u32_array(np,
- "synaptics,cap-button-codes",
- bdata->cap_button_map->map,
- bdata->cap_button_map->nbuttons);
- if (retval < 0) {
- bdata->cap_button_map->nbuttons = 0;
- bdata->cap_button_map->map = NULL;
- }
- } else {
- bdata->cap_button_map->nbuttons = 0;
- bdata->cap_button_map->map = NULL;
- }
-
- prop = of_find_property(np, "synaptics,vir-button-codes", NULL);
- if (prop && prop->length) {
- bdata->vir_button_map->map = devm_kzalloc(dev,
- prop->length,
- GFP_KERNEL);
- if (!bdata->vir_button_map->map)
- return -ENOMEM;
- bdata->vir_button_map->nbuttons = prop->length / sizeof(u32);
- bdata->vir_button_map->nbuttons /= 5;
- retval = of_property_read_u32_array(np,
- "synaptics,vir-button-codes",
- bdata->vir_button_map->map,
- bdata->vir_button_map->nbuttons * 5);
- if (retval < 0) {
- bdata->vir_button_map->nbuttons = 0;
- bdata->vir_button_map->map = NULL;
- }
- } else {
- bdata->vir_button_map->nbuttons = 0;
- bdata->vir_button_map->map = NULL;
- }
-
- return 0;
-}
-#endif
-
-static int synaptics_rmi4_spi_set_page(struct synaptics_rmi4_data *rmi4_data,
- unsigned short addr)
-{
- int retval;
- unsigned int index;
- unsigned int xfer_count = PAGE_SELECT_LEN + 1;
- unsigned char txbuf[xfer_count];
- unsigned char page;
- struct spi_message msg;
- struct spi_transfer xfers[xfer_count];
- struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent);
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- page = ((addr >> 8) & ~MASK_7BIT);
- if (page != rmi4_data->current_page) {
- spi_message_init(&msg);
-
- txbuf[0] = SPI_WRITE;
- txbuf[1] = MASK_8BIT;
- txbuf[2] = page;
-
- for (index = 0; index < xfer_count; index++) {
- memset(&xfers[index], 0, sizeof(struct spi_transfer));
- xfers[index].len = 1;
- xfers[index].delay_usecs = bdata->byte_delay_us;
- xfers[index].tx_buf = &txbuf[index];
- spi_message_add_tail(&xfers[index], &msg);
- }
-
- if (bdata->block_delay_us)
- xfers[index - 1].delay_usecs = bdata->block_delay_us;
-
- retval = spi_sync(spi, &msg);
- if (retval == 0) {
- rmi4_data->current_page = page;
- retval = PAGE_SELECT_LEN;
- } else {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to complete SPI transfer, error = %d\n",
- __func__, retval);
- }
- } else {
- retval = PAGE_SELECT_LEN;
- }
-
- return retval;
-}
-
-static int synaptics_rmi4_spi_read(struct synaptics_rmi4_data *rmi4_data,
- unsigned short addr, unsigned char *data, unsigned short length)
-{
- int retval;
- unsigned int index;
- unsigned int xfer_count = length + ADDRESS_WORD_LEN;
- unsigned char txbuf[ADDRESS_WORD_LEN];
- unsigned char *rxbuf = NULL;
- struct spi_message msg;
- struct spi_transfer *xfers = NULL;
- struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent);
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- spi_message_init(&msg);
-
- xfers = kcalloc(xfer_count, sizeof(struct spi_transfer), GFP_KERNEL);
- if (!xfers) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to allocate memory for xfers\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- txbuf[0] = (addr >> 8) | SPI_READ;
- txbuf[1] = addr & MASK_8BIT;
-
- rxbuf = kmalloc(length, GFP_KERNEL);
- if (!rxbuf) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to allocate memory for rxbuf\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- retval = synaptics_rmi4_spi_set_page(rmi4_data, addr);
- if (retval != PAGE_SELECT_LEN) {
- mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
- retval = -EIO;
- goto exit;
- }
-
- for (index = 0; index < xfer_count; index++) {
- xfers[index].len = 1;
- xfers[index].delay_usecs = bdata->byte_delay_us;
- if (index < ADDRESS_WORD_LEN)
- xfers[index].tx_buf = &txbuf[index];
- else
- xfers[index].rx_buf = &rxbuf[index - ADDRESS_WORD_LEN];
- spi_message_add_tail(&xfers[index], &msg);
- }
-
- if (bdata->block_delay_us)
- xfers[index - 1].delay_usecs = bdata->block_delay_us;
-
- retval = spi_sync(spi, &msg);
- if (retval == 0) {
- retval = secure_memcpy(data, length, rxbuf, length, length);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy data\n",
- __func__);
- } else {
- retval = length;
- }
- } else {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to complete SPI transfer, error = %d\n",
- __func__, retval);
- }
-
- mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
-
-exit:
- kfree(rxbuf);
- kfree(xfers);
-
- return retval;
-}
-
-static int synaptics_rmi4_spi_write(struct synaptics_rmi4_data *rmi4_data,
- unsigned short addr, unsigned char *data, unsigned short length)
-{
- int retval;
- unsigned int index;
- unsigned int xfer_count = length + ADDRESS_WORD_LEN;
- unsigned char *txbuf = NULL;
- struct spi_message msg;
- struct spi_transfer *xfers = NULL;
- struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent);
- const struct synaptics_dsx_board_data *bdata =
- rmi4_data->hw_if->board_data;
-
- spi_message_init(&msg);
-
- xfers = kcalloc(xfer_count, sizeof(struct spi_transfer), GFP_KERNEL);
- if (!xfers) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to allocate memory for xfers\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- txbuf = kmalloc(xfer_count, GFP_KERNEL);
- if (!txbuf) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to allocate memory for txbuf\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- txbuf[0] = (addr >> 8) & ~SPI_READ;
- txbuf[1] = addr & MASK_8BIT;
- retval = secure_memcpy(&txbuf[ADDRESS_WORD_LEN],
- xfer_count - ADDRESS_WORD_LEN, data, length, length);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy data\n",
- __func__);
- goto exit;
- }
-
- mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
-
- retval = synaptics_rmi4_spi_set_page(rmi4_data, addr);
- if (retval != PAGE_SELECT_LEN) {
- mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
- retval = -EIO;
- goto exit;
- }
-
- for (index = 0; index < xfer_count; index++) {
- xfers[index].len = 1;
- xfers[index].delay_usecs = bdata->byte_delay_us;
- xfers[index].tx_buf = &txbuf[index];
- spi_message_add_tail(&xfers[index], &msg);
- }
-
- if (bdata->block_delay_us)
- xfers[index - 1].delay_usecs = bdata->block_delay_us;
-
- retval = spi_sync(spi, &msg);
- if (retval == 0) {
- retval = length;
- } else {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to complete SPI transfer, error = %d\n",
- __func__, retval);
- }
-
- mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
-
-exit:
- kfree(txbuf);
- kfree(xfers);
-
- return retval;
-}
-
-static struct synaptics_dsx_bus_access bus_access = {
- .type = BUS_SPI,
- .read = synaptics_rmi4_spi_read,
- .write = synaptics_rmi4_spi_write,
-};
-
-static struct synaptics_dsx_hw_interface hw_if;
-
-static struct platform_device *synaptics_dsx_spi_device;
-
-static void synaptics_rmi4_spi_dev_release(struct device *dev)
-{
- kfree(synaptics_dsx_spi_device);
-
- return;
-}
-
-static int synaptics_rmi4_spi_probe(struct spi_device *spi)
-{
- int retval;
-
- if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) {
- dev_err(&spi->dev,
- "%s: Full duplex not supported by host\n",
- __func__);
- return -EIO;
- }
-
- synaptics_dsx_spi_device = kzalloc(
- sizeof(struct platform_device),
- GFP_KERNEL);
- if (!synaptics_dsx_spi_device) {
- dev_err(&spi->dev,
- "%s: Failed to allocate memory for synaptics_dsx_spi_device\n",
- __func__);
- return -ENOMEM;
- }
-
-#ifdef CONFIG_OF
- if (spi->dev.of_node) {
- hw_if.board_data = devm_kzalloc(&spi->dev,
- sizeof(struct synaptics_dsx_board_data),
- GFP_KERNEL);
- if (!hw_if.board_data) {
- dev_err(&spi->dev,
- "%s: Failed to allocate memory for board data\n",
- __func__);
- return -ENOMEM;
- }
- hw_if.board_data->cap_button_map = devm_kzalloc(&spi->dev,
- sizeof(struct synaptics_dsx_button_map),
- GFP_KERNEL);
- if (!hw_if.board_data->cap_button_map) {
- dev_err(&spi->dev,
- "%s: Failed to allocate memory for 0D button map\n",
- __func__);
- return -ENOMEM;
- }
- hw_if.board_data->vir_button_map = devm_kzalloc(&spi->dev,
- sizeof(struct synaptics_dsx_button_map),
- GFP_KERNEL);
- if (!hw_if.board_data->vir_button_map) {
- dev_err(&spi->dev,
- "%s: Failed to allocate memory for virtual button map\n",
- __func__);
- return -ENOMEM;
- }
- parse_dt(&spi->dev, hw_if.board_data);
- }
-#else
- hw_if.board_data = spi->dev.platform_data;
-#endif
-
- hw_if.bus_access = &bus_access;
-
- spi->bits_per_word = 8;
- spi->mode = SPI_MODE_3;
-
- retval = spi_setup(spi);
- if (retval < 0) {
- dev_err(&spi->dev,
- "%s: Failed to perform SPI setup\n",
- __func__);
- return retval;
- }
-
- synaptics_dsx_spi_device->name = PLATFORM_DRIVER_NAME;
- synaptics_dsx_spi_device->id = 0;
- synaptics_dsx_spi_device->num_resources = 0;
- synaptics_dsx_spi_device->dev.parent = &spi->dev;
- synaptics_dsx_spi_device->dev.platform_data = &hw_if;
- synaptics_dsx_spi_device->dev.release = synaptics_rmi4_spi_dev_release;
-
- retval = platform_device_register(synaptics_dsx_spi_device);
- if (retval) {
- dev_err(&spi->dev,
- "%s: Failed to register platform device\n",
- __func__);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int synaptics_rmi4_spi_remove(struct spi_device *spi)
-{
- platform_device_unregister(synaptics_dsx_spi_device);
-
- return 0;
-}
-
-#ifdef CONFIG_OF
-static struct of_device_id synaptics_rmi4_of_match_table[] = {
- {
- .compatible = "synaptics,dsx-spi",
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, synaptics_rmi4_of_match_table);
-#else
-#define synaptics_rmi4_of_match_table NULL
-#endif
-
-static struct spi_driver synaptics_rmi4_spi_driver = {
- .driver = {
- .name = SPI_DRIVER_NAME,
- .owner = THIS_MODULE,
- .of_match_table = synaptics_rmi4_of_match_table,
- },
- .probe = synaptics_rmi4_spi_probe,
- .remove = synaptics_rmi4_spi_remove,
-};
-
-
-int synaptics_rmi4_bus_init_v26(void)
-{
- return spi_register_driver(&synaptics_rmi4_spi_driver);
-}
-EXPORT_SYMBOL(synaptics_rmi4_bus_init_v26);
-
-void synaptics_rmi4_bus_exit_v26(void)
-{
- spi_unregister_driver(&synaptics_rmi4_spi_driver);
-
- return;
-}
-EXPORT_SYMBOL(synaptics_rmi4_bus_exit_v26);
-
-MODULE_AUTHOR("Synaptics, Inc.");
-MODULE_DESCRIPTION("Synaptics DSX SPI Bus Support Module");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c
deleted file mode 100644
index d42b23e46d0a..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_test_reporting.c
+++ /dev/null
@@ -1,4162 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/ctype.h>
-#include <linux/hrtimer.h>
-#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx_v2_6.h>
-#include "synaptics_dsx_core.h"
-
-#define SYSFS_FOLDER_NAME "f54"
-
-#define GET_REPORT_TIMEOUT_S 3
-#define CALIBRATION_TIMEOUT_S 10
-#define COMMAND_TIMEOUT_100MS 20
-
-#define NO_SLEEP_OFF (0 << 2)
-#define NO_SLEEP_ON (1 << 2)
-
-#define STATUS_IDLE 0
-#define STATUS_BUSY 1
-#define STATUS_ERROR 2
-
-#define REPORT_INDEX_OFFSET 1
-#define REPORT_DATA_OFFSET 3
-
-#define SENSOR_RX_MAPPING_OFFSET 1
-#define SENSOR_TX_MAPPING_OFFSET 2
-
-#define COMMAND_GET_REPORT 1
-#define COMMAND_FORCE_CAL 2
-#define COMMAND_FORCE_UPDATE 4
-
-#define CONTROL_NO_AUTO_CAL 1
-
-#define CONTROL_0_SIZE 1
-#define CONTROL_1_SIZE 1
-#define CONTROL_2_SIZE 2
-#define CONTROL_3_SIZE 1
-#define CONTROL_4_6_SIZE 3
-#define CONTROL_7_SIZE 1
-#define CONTROL_8_9_SIZE 3
-#define CONTROL_10_SIZE 1
-#define CONTROL_11_SIZE 2
-#define CONTROL_12_13_SIZE 2
-#define CONTROL_14_SIZE 1
-#define CONTROL_15_SIZE 1
-#define CONTROL_16_SIZE 1
-#define CONTROL_17_SIZE 1
-#define CONTROL_18_SIZE 1
-#define CONTROL_19_SIZE 1
-#define CONTROL_20_SIZE 1
-#define CONTROL_21_SIZE 2
-#define CONTROL_22_26_SIZE 7
-#define CONTROL_27_SIZE 1
-#define CONTROL_28_SIZE 2
-#define CONTROL_29_SIZE 1
-#define CONTROL_30_SIZE 1
-#define CONTROL_31_SIZE 1
-#define CONTROL_32_35_SIZE 8
-#define CONTROL_36_SIZE 1
-#define CONTROL_37_SIZE 1
-#define CONTROL_38_SIZE 1
-#define CONTROL_39_SIZE 1
-#define CONTROL_40_SIZE 1
-#define CONTROL_41_SIZE 1
-#define CONTROL_42_SIZE 2
-#define CONTROL_43_54_SIZE 13
-#define CONTROL_55_56_SIZE 2
-#define CONTROL_57_SIZE 1
-#define CONTROL_58_SIZE 1
-#define CONTROL_59_SIZE 2
-#define CONTROL_60_62_SIZE 3
-#define CONTROL_63_SIZE 1
-#define CONTROL_64_67_SIZE 4
-#define CONTROL_68_73_SIZE 8
-#define CONTROL_74_SIZE 2
-#define CONTROL_75_SIZE 1
-#define CONTROL_76_SIZE 1
-#define CONTROL_77_78_SIZE 2
-#define CONTROL_79_83_SIZE 5
-#define CONTROL_84_85_SIZE 2
-#define CONTROL_86_SIZE 1
-#define CONTROL_87_SIZE 1
-#define CONTROL_88_SIZE 1
-#define CONTROL_89_SIZE 1
-#define CONTROL_90_SIZE 1
-#define CONTROL_91_SIZE 1
-#define CONTROL_92_SIZE 1
-#define CONTROL_93_SIZE 1
-#define CONTROL_94_SIZE 1
-#define CONTROL_95_SIZE 1
-#define CONTROL_96_SIZE 1
-#define CONTROL_97_SIZE 1
-#define CONTROL_98_SIZE 1
-#define CONTROL_99_SIZE 1
-#define CONTROL_100_SIZE 1
-#define CONTROL_101_SIZE 1
-#define CONTROL_102_SIZE 1
-#define CONTROL_103_SIZE 1
-#define CONTROL_104_SIZE 1
-#define CONTROL_105_SIZE 1
-#define CONTROL_106_SIZE 1
-#define CONTROL_107_SIZE 1
-#define CONTROL_108_SIZE 1
-#define CONTROL_109_SIZE 1
-#define CONTROL_110_SIZE 1
-#define CONTROL_111_SIZE 1
-#define CONTROL_112_SIZE 1
-#define CONTROL_113_SIZE 1
-#define CONTROL_114_SIZE 1
-#define CONTROL_115_SIZE 1
-#define CONTROL_116_SIZE 1
-#define CONTROL_117_SIZE 1
-#define CONTROL_118_SIZE 1
-#define CONTROL_119_SIZE 1
-#define CONTROL_120_SIZE 1
-#define CONTROL_121_SIZE 1
-#define CONTROL_122_SIZE 1
-#define CONTROL_123_SIZE 1
-#define CONTROL_124_SIZE 1
-#define CONTROL_125_SIZE 1
-#define CONTROL_126_SIZE 1
-#define CONTROL_127_SIZE 1
-#define CONTROL_128_SIZE 1
-#define CONTROL_129_SIZE 1
-#define CONTROL_130_SIZE 1
-#define CONTROL_131_SIZE 1
-#define CONTROL_132_SIZE 1
-#define CONTROL_133_SIZE 1
-#define CONTROL_134_SIZE 1
-#define CONTROL_135_SIZE 1
-#define CONTROL_136_SIZE 1
-#define CONTROL_137_SIZE 1
-#define CONTROL_138_SIZE 1
-#define CONTROL_139_SIZE 1
-#define CONTROL_140_SIZE 1
-#define CONTROL_141_SIZE 1
-#define CONTROL_142_SIZE 1
-#define CONTROL_143_SIZE 1
-#define CONTROL_144_SIZE 1
-#define CONTROL_145_SIZE 1
-#define CONTROL_146_SIZE 1
-#define CONTROL_147_SIZE 1
-#define CONTROL_148_SIZE 1
-#define CONTROL_149_SIZE 1
-#define CONTROL_163_SIZE 1
-#define CONTROL_165_SIZE 1
-#define CONTROL_167_SIZE 1
-#define CONTROL_176_SIZE 1
-#define CONTROL_179_SIZE 1
-#define CONTROL_188_SIZE 1
-
-#define HIGH_RESISTANCE_DATA_SIZE 6
-#define FULL_RAW_CAP_MIN_MAX_DATA_SIZE 4
-#define TRX_OPEN_SHORT_DATA_SIZE 7
-
-#define concat(a, b) a##b
-
-#define attrify(propname) (&dev_attr_##propname.attr)
-
-#define show_prototype(propname)\
-static ssize_t concat(test_sysfs, _##propname##_show)(\
- struct device *dev,\
- struct device_attribute *attr,\
- char *buf);
-
-#define store_prototype(propname)\
-static ssize_t concat(test_sysfs, _##propname##_store)(\
- struct device *dev,\
- struct device_attribute *attr,\
- const char *buf, size_t count);
-
-#define show_store_prototype(propname)\
-static ssize_t concat(test_sysfs, _##propname##_show)(\
- struct device *dev,\
- struct device_attribute *attr,\
- char *buf);\
-\
-static ssize_t concat(test_sysfs, _##propname##_store)(\
- struct device *dev,\
- struct device_attribute *attr,\
- const char *buf, size_t count);\
-\
-static struct device_attribute dev_attr_##propname =\
- __ATTR(propname, (S_IRUGO | S_IWUGO),\
- concat(test_sysfs, _##propname##_show),\
- concat(test_sysfs, _##propname##_store));
-
-#define disable_cbc(ctrl_num)\
-do {\
- retval = synaptics_rmi4_reg_read(rmi4_data,\
- f54->control.ctrl_num->address,\
- f54->control.ctrl_num->data,\
- sizeof(f54->control.ctrl_num->data));\
- if (retval < 0) {\
- dev_err(rmi4_data->pdev->dev.parent,\
- "%s: Failed to disable CBC (" #ctrl_num ")\n",\
- __func__);\
- return retval;\
- } \
- f54->control.ctrl_num->cbc_tx_carrier_selection = 0;\
- retval = synaptics_rmi4_reg_write(rmi4_data,\
- f54->control.ctrl_num->address,\
- f54->control.ctrl_num->data,\
- sizeof(f54->control.ctrl_num->data));\
- if (retval < 0) {\
- dev_err(rmi4_data->pdev->dev.parent,\
- "%s: Failed to disable CBC (" #ctrl_num ")\n",\
- __func__);\
- return retval;\
- } \
-} while (0)
-
-enum f54_report_types {
- F54_8BIT_IMAGE = 1,
- F54_16BIT_IMAGE = 2,
- F54_RAW_16BIT_IMAGE = 3,
- F54_HIGH_RESISTANCE = 4,
- F54_TX_TO_TX_SHORTS = 5,
- F54_RX_TO_RX_SHORTS_1 = 7,
- F54_TRUE_BASELINE = 9,
- F54_FULL_RAW_CAP_MIN_MAX = 13,
- F54_RX_OPENS_1 = 14,
- F54_TX_OPENS = 15,
- F54_TX_TO_GND_SHORTS = 16,
- F54_RX_TO_RX_SHORTS_2 = 17,
- F54_RX_OPENS_2 = 18,
- F54_FULL_RAW_CAP = 19,
- F54_FULL_RAW_CAP_NO_RX_COUPLING = 20,
- F54_SENSOR_SPEED = 22,
- F54_ADC_RANGE = 23,
- F54_TRX_OPENS = 24,
- F54_TRX_TO_GND_SHORTS = 25,
- F54_TRX_SHORTS = 26,
- F54_ABS_RAW_CAP = 38,
- F54_ABS_DELTA_CAP = 40,
- F54_ABS_HYBRID_DELTA_CAP = 59,
- F54_ABS_HYBRID_RAW_CAP = 63,
- F54_AMP_FULL_RAW_CAP = 78,
- F54_AMP_RAW_ADC = 83,
- INVALID_REPORT_TYPE = -1,
-};
-
-enum f54_afe_cal {
- F54_AFE_CAL,
- F54_AFE_IS_CAL,
-};
-
-struct f54_query {
- union {
- struct {
- /* query 0 */
- unsigned char num_of_rx_electrodes;
-
- /* query 1 */
- unsigned char num_of_tx_electrodes;
-
- /* query 2 */
- unsigned char f54_query2_b0__1:2;
- unsigned char has_baseline:1;
- unsigned char has_image8:1;
- unsigned char f54_query2_b4__5:2;
- unsigned char has_image16:1;
- unsigned char f54_query2_b7:1;
-
- /* queries 3.0 and 3.1 */
- unsigned short clock_rate;
-
- /* query 4 */
- unsigned char touch_controller_family;
-
- /* query 5 */
- unsigned char has_pixel_touch_threshold_adjustment:1;
- unsigned char f54_query5_b1__7:7;
-
- /* query 6 */
- unsigned char has_sensor_assignment:1;
- unsigned char has_interference_metric:1;
- unsigned char has_sense_frequency_control:1;
- unsigned char has_firmware_noise_mitigation:1;
- unsigned char has_ctrl11:1;
- unsigned char has_two_byte_report_rate:1;
- unsigned char has_one_byte_report_rate:1;
- unsigned char has_relaxation_control:1;
-
- /* query 7 */
- unsigned char curve_compensation_mode:2;
- unsigned char f54_query7_b2__7:6;
-
- /* query 8 */
- unsigned char f54_query8_b0:1;
- unsigned char has_iir_filter:1;
- unsigned char has_cmn_removal:1;
- unsigned char has_cmn_maximum:1;
- unsigned char has_touch_hysteresis:1;
- unsigned char has_edge_compensation:1;
- unsigned char has_per_frequency_noise_control:1;
- unsigned char has_enhanced_stretch:1;
-
- /* query 9 */
- unsigned char has_force_fast_relaxation:1;
- unsigned char has_multi_metric_state_machine:1;
- unsigned char has_signal_clarity:1;
- unsigned char has_variance_metric:1;
- unsigned char has_0d_relaxation_control:1;
- unsigned char has_0d_acquisition_control:1;
- unsigned char has_status:1;
- unsigned char has_slew_metric:1;
-
- /* query 10 */
- unsigned char has_h_blank:1;
- unsigned char has_v_blank:1;
- unsigned char has_long_h_blank:1;
- unsigned char has_startup_fast_relaxation:1;
- unsigned char has_esd_control:1;
- unsigned char has_noise_mitigation2:1;
- unsigned char has_noise_state:1;
- unsigned char has_energy_ratio_relaxation:1;
-
- /* query 11 */
- unsigned char has_excessive_noise_reporting:1;
- unsigned char has_slew_option:1;
- unsigned char has_two_overhead_bursts:1;
- unsigned char has_query13:1;
- unsigned char has_one_overhead_burst:1;
- unsigned char f54_query11_b5:1;
- unsigned char has_ctrl88:1;
- unsigned char has_query15:1;
-
- /* query 12 */
- unsigned char number_of_sensing_frequencies:4;
- unsigned char f54_query12_b4__7:4;
- } __packed;
- unsigned char data[14];
- };
-};
-
-struct f54_query_13 {
- union {
- struct {
- unsigned char has_ctrl86:1;
- unsigned char has_ctrl87:1;
- unsigned char has_ctrl87_sub0:1;
- unsigned char has_ctrl87_sub1:1;
- unsigned char has_ctrl87_sub2:1;
- unsigned char has_cidim:1;
- unsigned char has_noise_mitigation_enhancement:1;
- unsigned char has_rail_im:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_15 {
- union {
- struct {
- unsigned char has_ctrl90:1;
- unsigned char has_transmit_strength:1;
- unsigned char has_ctrl87_sub3:1;
- unsigned char has_query16:1;
- unsigned char has_query20:1;
- unsigned char has_query21:1;
- unsigned char has_query22:1;
- unsigned char has_query25:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_16 {
- union {
- struct {
- unsigned char has_query17:1;
- unsigned char has_data17:1;
- unsigned char has_ctrl92:1;
- unsigned char has_ctrl93:1;
- unsigned char has_ctrl94_query18:1;
- unsigned char has_ctrl95_query19:1;
- unsigned char has_ctrl99:1;
- unsigned char has_ctrl100:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_21 {
- union {
- struct {
- unsigned char has_abs_rx:1;
- unsigned char has_abs_tx:1;
- unsigned char has_ctrl91:1;
- unsigned char has_ctrl96:1;
- unsigned char has_ctrl97:1;
- unsigned char has_ctrl98:1;
- unsigned char has_data19:1;
- unsigned char has_query24_data18:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_22 {
- union {
- struct {
- unsigned char has_packed_image:1;
- unsigned char has_ctrl101:1;
- unsigned char has_dynamic_sense_display_ratio:1;
- unsigned char has_query23:1;
- unsigned char has_ctrl103_query26:1;
- unsigned char has_ctrl104:1;
- unsigned char has_ctrl105:1;
- unsigned char has_query28:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_23 {
- union {
- struct {
- unsigned char has_ctrl102:1;
- unsigned char has_ctrl102_sub1:1;
- unsigned char has_ctrl102_sub2:1;
- unsigned char has_ctrl102_sub4:1;
- unsigned char has_ctrl102_sub5:1;
- unsigned char has_ctrl102_sub9:1;
- unsigned char has_ctrl102_sub10:1;
- unsigned char has_ctrl102_sub11:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_25 {
- union {
- struct {
- unsigned char has_ctrl106:1;
- unsigned char has_ctrl102_sub12:1;
- unsigned char has_ctrl107:1;
- unsigned char has_ctrl108:1;
- unsigned char has_ctrl109:1;
- unsigned char has_data20:1;
- unsigned char f54_query25_b6:1;
- unsigned char has_query27:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_27 {
- union {
- struct {
- unsigned char has_ctrl110:1;
- unsigned char has_data21:1;
- unsigned char has_ctrl111:1;
- unsigned char has_ctrl112:1;
- unsigned char has_ctrl113:1;
- unsigned char has_data22:1;
- unsigned char has_ctrl114:1;
- unsigned char has_query29:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_29 {
- union {
- struct {
- unsigned char has_ctrl115:1;
- unsigned char has_ground_ring_options:1;
- unsigned char has_lost_bursts_tuning:1;
- unsigned char has_aux_exvcom2_select:1;
- unsigned char has_ctrl116:1;
- unsigned char has_data23:1;
- unsigned char has_ctrl117:1;
- unsigned char has_query30:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_30 {
- union {
- struct {
- unsigned char has_ctrl118:1;
- unsigned char has_ctrl119:1;
- unsigned char has_ctrl120:1;
- unsigned char has_ctrl121:1;
- unsigned char has_ctrl122_query31:1;
- unsigned char has_ctrl123:1;
- unsigned char f54_query30_b6:1;
- unsigned char has_query32:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_32 {
- union {
- struct {
- unsigned char has_ctrl125:1;
- unsigned char has_ctrl126:1;
- unsigned char has_ctrl127:1;
- unsigned char has_abs_charge_pump_disable:1;
- unsigned char has_query33:1;
- unsigned char has_data24:1;
- unsigned char has_query34:1;
- unsigned char has_query35:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_33 {
- union {
- struct {
- unsigned char f54_query33_b0:1;
- unsigned char f54_query33_b1:1;
- unsigned char f54_query33_b2:1;
- unsigned char f54_query33_b3:1;
- unsigned char has_ctrl132:1;
- unsigned char has_ctrl133:1;
- unsigned char has_ctrl134:1;
- unsigned char has_query36:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_35 {
- union {
- struct {
- unsigned char has_data25:1;
- unsigned char f54_query35_b1:1;
- unsigned char f54_query35_b2:1;
- unsigned char has_ctrl137:1;
- unsigned char has_ctrl138:1;
- unsigned char has_ctrl139:1;
- unsigned char has_data26:1;
- unsigned char has_ctrl140:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_36 {
- union {
- struct {
- unsigned char f54_query36_b0:1;
- unsigned char has_ctrl142:1;
- unsigned char has_query37:1;
- unsigned char has_ctrl143:1;
- unsigned char has_ctrl144:1;
- unsigned char has_ctrl145:1;
- unsigned char has_ctrl146:1;
- unsigned char has_query38:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_38 {
- union {
- struct {
- unsigned char has_ctrl147:1;
- unsigned char has_ctrl148:1;
- unsigned char has_ctrl149:1;
- unsigned char f54_query38_b3__6:4;
- unsigned char has_query39:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_39 {
- union {
- struct {
- unsigned char f54_query39_b0__6:7;
- unsigned char has_query40:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_40 {
- union {
- struct {
- unsigned char f54_query40_b0:1;
- unsigned char has_ctrl163_query41:1;
- unsigned char f54_query40_b2:1;
- unsigned char has_ctrl165_query42:1;
- unsigned char f54_query40_b4:1;
- unsigned char has_ctrl167:1;
- unsigned char f54_query40_b6:1;
- unsigned char has_query43:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_43 {
- union {
- struct {
- unsigned char f54_query43_b0__6:7;
- unsigned char has_query46:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_46 {
- union {
- struct {
- unsigned char has_ctrl176:1;
- unsigned char f54_query46_b1:1;
- unsigned char has_ctrl179:1;
- unsigned char f54_query46_b3:1;
- unsigned char has_data27:1;
- unsigned char has_data28:1;
- unsigned char f54_query46_b6:1;
- unsigned char has_query47:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_47 {
- union {
- struct {
- unsigned char f54_query47_b0__6:7;
- unsigned char has_query49:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_49 {
- union {
- struct {
- unsigned char f54_query49_b0__1:2;
- unsigned char has_ctrl188:1;
- unsigned char has_data31:1;
- unsigned char f54_query49_b4__6:3;
- unsigned char has_query50:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_50 {
- union {
- struct {
- unsigned char f54_query50_b0__6:7;
- unsigned char has_query51:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_query_51 {
- union {
- struct {
- unsigned char f54_query51_b0__4:5;
- unsigned char has_query53_query54_ctrl198:1;
- unsigned char f54_query51_b6__7:2;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f54_data_31 {
- union {
- struct {
- unsigned char is_calibration_crc:1;
- unsigned char calibration_crc:1;
- unsigned char short_test_row_number:5;
- } __packed;
- struct {
- unsigned char data[1];
- unsigned short address;
- } __packed;
- };
-};
-
-struct f54_control_7 {
- union {
- struct {
- unsigned char cbc_cap:3;
- unsigned char cbc_polarity:1;
- unsigned char cbc_tx_carrier_selection:1;
- unsigned char f54_ctrl7_b5__7:3;
- } __packed;
- struct {
- unsigned char data[1];
- unsigned short address;
- } __packed;
- };
-};
-
-struct f54_control_41 {
- union {
- struct {
- unsigned char no_signal_clarity:1;
- unsigned char f54_ctrl41_b1__7:7;
- } __packed;
- struct {
- unsigned char data[1];
- unsigned short address;
- } __packed;
- };
-};
-
-struct f54_control_57 {
- union {
- struct {
- unsigned char cbc_cap:3;
- unsigned char cbc_polarity:1;
- unsigned char cbc_tx_carrier_selection:1;
- unsigned char f54_ctrl57_b5__7:3;
- } __packed;
- struct {
- unsigned char data[1];
- unsigned short address;
- } __packed;
- };
-};
-
-struct f54_control_86 {
- union {
- struct {
- unsigned char enable_high_noise_state:1;
- unsigned char dynamic_sense_display_ratio:2;
- unsigned char f54_ctrl86_b3__7:5;
- } __packed;
- struct {
- unsigned char data[1];
- unsigned short address;
- } __packed;
- };
-};
-
-struct f54_control_88 {
- union {
- struct {
- unsigned char tx_low_reference_polarity:1;
- unsigned char tx_high_reference_polarity:1;
- unsigned char abs_low_reference_polarity:1;
- unsigned char abs_polarity:1;
- unsigned char cbc_polarity:1;
- unsigned char cbc_tx_carrier_selection:1;
- unsigned char charge_pump_enable:1;
- unsigned char cbc_abs_auto_servo:1;
- } __packed;
- struct {
- unsigned char data[1];
- unsigned short address;
- } __packed;
- };
-};
-
-struct f54_control_110 {
- union {
- struct {
- unsigned char active_stylus_rx_feedback_cap;
- unsigned char active_stylus_rx_feedback_cap_reference;
- unsigned char active_stylus_low_reference;
- unsigned char active_stylus_high_reference;
- unsigned char active_stylus_gain_control;
- unsigned char active_stylus_gain_control_reference;
- unsigned char active_stylus_timing_mode;
- unsigned char active_stylus_discovery_bursts;
- unsigned char active_stylus_detection_bursts;
- unsigned char active_stylus_discovery_noise_multiplier;
- unsigned char active_stylus_detection_envelope_min;
- unsigned char active_stylus_detection_envelope_max;
- unsigned char active_stylus_lose_count;
- } __packed;
- struct {
- unsigned char data[13];
- unsigned short address;
- } __packed;
- };
-};
-
-struct f54_control_149 {
- union {
- struct {
- unsigned char trans_cbc_global_cap_enable:1;
- unsigned char f54_ctrl149_b1__7:7;
- } __packed;
- struct {
- unsigned char data[1];
- unsigned short address;
- } __packed;
- };
-};
-
-struct f54_control_188 {
- union {
- struct {
- unsigned char start_calibration:1;
- unsigned char start_is_calibration:1;
- unsigned char frequency:2;
- unsigned char start_production_test:1;
- unsigned char short_test_calibration:1;
- unsigned char f54_ctrl188_b7:1;
- } __packed;
- struct {
- unsigned char data[1];
- unsigned short address;
- } __packed;
- };
-};
-
-struct f54_control {
- struct f54_control_7 *reg_7;
- struct f54_control_41 *reg_41;
- struct f54_control_57 *reg_57;
- struct f54_control_86 *reg_86;
- struct f54_control_88 *reg_88;
- struct f54_control_110 *reg_110;
- struct f54_control_149 *reg_149;
- struct f54_control_188 *reg_188;
-};
-
-struct synaptics_rmi4_f54_handle {
- bool no_auto_cal;
- bool skip_preparation;
- unsigned char status;
- unsigned char intr_mask;
- unsigned char intr_reg_num;
- unsigned char tx_assigned;
- unsigned char rx_assigned;
- unsigned char *report_data;
- unsigned short query_base_addr;
- unsigned short control_base_addr;
- unsigned short data_base_addr;
- unsigned short command_base_addr;
- unsigned short fifoindex;
- unsigned int report_size;
- unsigned int data_buffer_size;
- unsigned int data_pos;
- enum f54_report_types report_type;
- struct f54_query query;
- struct f54_query_13 query_13;
- struct f54_query_15 query_15;
- struct f54_query_16 query_16;
- struct f54_query_21 query_21;
- struct f54_query_22 query_22;
- struct f54_query_23 query_23;
- struct f54_query_25 query_25;
- struct f54_query_27 query_27;
- struct f54_query_29 query_29;
- struct f54_query_30 query_30;
- struct f54_query_32 query_32;
- struct f54_query_33 query_33;
- struct f54_query_35 query_35;
- struct f54_query_36 query_36;
- struct f54_query_38 query_38;
- struct f54_query_39 query_39;
- struct f54_query_40 query_40;
- struct f54_query_43 query_43;
- struct f54_query_46 query_46;
- struct f54_query_47 query_47;
- struct f54_query_49 query_49;
- struct f54_query_50 query_50;
- struct f54_query_51 query_51;
- struct f54_data_31 data_31;
- struct f54_control control;
- struct mutex status_mutex;
- struct kobject *sysfs_dir;
- struct hrtimer watchdog;
- struct work_struct timeout_work;
- struct work_struct test_report_work;
- struct workqueue_struct *test_report_workqueue;
- struct synaptics_rmi4_data *rmi4_data;
-};
-
-struct f55_query {
- union {
- struct {
- /* query 0 */
- unsigned char num_of_rx_electrodes;
-
- /* query 1 */
- unsigned char num_of_tx_electrodes;
-
- /* query 2 */
- unsigned char has_sensor_assignment:1;
- unsigned char has_edge_compensation:1;
- unsigned char curve_compensation_mode:2;
- unsigned char has_ctrl6:1;
- unsigned char has_alternate_transmitter_assignment:1;
- unsigned char has_single_layer_multi_touch:1;
- unsigned char has_query5:1;
- } __packed;
- unsigned char data[3];
- };
-};
-
-struct f55_query_3 {
- union {
- struct {
- unsigned char has_ctrl8:1;
- unsigned char has_ctrl9:1;
- unsigned char has_oncell_pattern_support:1;
- unsigned char has_data0:1;
- unsigned char has_single_wide_pattern_support:1;
- unsigned char has_mirrored_tx_pattern_support:1;
- unsigned char has_discrete_pattern_support:1;
- unsigned char has_query9:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f55_query_5 {
- union {
- struct {
- unsigned char has_corner_compensation:1;
- unsigned char has_ctrl12:1;
- unsigned char has_trx_configuration:1;
- unsigned char has_ctrl13:1;
- unsigned char f55_query5_b4:1;
- unsigned char has_ctrl14:1;
- unsigned char has_basis_function:1;
- unsigned char has_query17:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f55_query_17 {
- union {
- struct {
- unsigned char f55_query17_b0:1;
- unsigned char has_ctrl16:1;
- unsigned char f55_query17_b2:1;
- unsigned char has_ctrl17:1;
- unsigned char f55_query17_b4__6:3;
- unsigned char has_query18:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f55_query_18 {
- union {
- struct {
- unsigned char f55_query18_b0__6:7;
- unsigned char has_query22:1;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f55_query_22 {
- union {
- struct {
- unsigned char f55_query22_b0:1;
- unsigned char has_query23:1;
- unsigned char has_guard_disable:1;
- unsigned char has_ctrl30:1;
- unsigned char f55_query22_b4__7:4;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct f55_query_23 {
- union {
- struct {
- unsigned char amp_sensor_enabled:1;
- unsigned char image_transposed:1;
- unsigned char first_column_at_left_side:1;
- unsigned char size_of_column2mux:5;
- } __packed;
- unsigned char data[1];
- };
-};
-
-struct synaptics_rmi4_f55_handle {
- bool amp_sensor;
- unsigned char size_of_column2mux;
- unsigned char *tx_assignment;
- unsigned char *rx_assignment;
- unsigned short query_base_addr;
- unsigned short control_base_addr;
- unsigned short data_base_addr;
- unsigned short command_base_addr;
- struct f55_query query;
- struct f55_query_3 query_3;
- struct f55_query_5 query_5;
- struct f55_query_17 query_17;
- struct f55_query_18 query_18;
- struct f55_query_22 query_22;
- struct f55_query_23 query_23;
-};
-
-show_prototype(num_of_mapped_tx)
-show_prototype(num_of_mapped_rx)
-show_prototype(tx_mapping)
-show_prototype(rx_mapping)
-show_prototype(report_size)
-show_prototype(status)
-store_prototype(do_preparation)
-store_prototype(force_cal)
-store_prototype(get_report)
-store_prototype(resume_touch)
-store_prototype(do_afe_calibration)
-show_store_prototype(report_type)
-show_store_prototype(fifoindex)
-show_store_prototype(no_auto_cal)
-show_store_prototype(read_report)
-
-static struct attribute *attrs[] = {
- attrify(num_of_mapped_tx),
- attrify(num_of_mapped_rx),
- attrify(tx_mapping),
- attrify(rx_mapping),
- attrify(report_size),
- attrify(status),
- attrify(do_preparation),
- attrify(force_cal),
- attrify(get_report),
- attrify(resume_touch),
- attrify(do_afe_calibration),
- attrify(report_type),
- attrify(fifoindex),
- attrify(no_auto_cal),
- attrify(read_report),
- NULL,
-};
-
-static struct attribute_group attr_group = {
- .attrs = attrs,
-};
-
-static ssize_t test_sysfs_data_read(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count);
-
-static struct bin_attribute test_report_data = {
- .attr = {
- .name = "report_data",
- .mode = S_IRUGO,
- },
- .size = 0,
- .read = test_sysfs_data_read,
-};
-
-static struct synaptics_rmi4_f54_handle *f54;
-static struct synaptics_rmi4_f55_handle *f55;
-
-DECLARE_COMPLETION(test_remove_complete);
-
-static bool test_report_type_valid(enum f54_report_types report_type)
-{
- switch (report_type) {
- case F54_8BIT_IMAGE:
- case F54_16BIT_IMAGE:
- case F54_RAW_16BIT_IMAGE:
- case F54_HIGH_RESISTANCE:
- case F54_TX_TO_TX_SHORTS:
- case F54_RX_TO_RX_SHORTS_1:
- case F54_TRUE_BASELINE:
- case F54_FULL_RAW_CAP_MIN_MAX:
- case F54_RX_OPENS_1:
- case F54_TX_OPENS:
- case F54_TX_TO_GND_SHORTS:
- case F54_RX_TO_RX_SHORTS_2:
- case F54_RX_OPENS_2:
- case F54_FULL_RAW_CAP:
- case F54_FULL_RAW_CAP_NO_RX_COUPLING:
- case F54_SENSOR_SPEED:
- case F54_ADC_RANGE:
- case F54_TRX_OPENS:
- case F54_TRX_TO_GND_SHORTS:
- case F54_TRX_SHORTS:
- case F54_ABS_RAW_CAP:
- case F54_ABS_DELTA_CAP:
- case F54_ABS_HYBRID_DELTA_CAP:
- case F54_ABS_HYBRID_RAW_CAP:
- case F54_AMP_FULL_RAW_CAP:
- case F54_AMP_RAW_ADC:
- return true;
- break;
- default:
- f54->report_type = INVALID_REPORT_TYPE;
- f54->report_size = 0;
- return false;
- }
-}
-
-static void test_set_report_size(void)
-{
- int retval;
- unsigned char tx = f54->tx_assigned;
- unsigned char rx = f54->rx_assigned;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- switch (f54->report_type) {
- case F54_8BIT_IMAGE:
- f54->report_size = tx * rx;
- break;
- case F54_16BIT_IMAGE:
- case F54_RAW_16BIT_IMAGE:
- case F54_TRUE_BASELINE:
- case F54_FULL_RAW_CAP:
- case F54_FULL_RAW_CAP_NO_RX_COUPLING:
- case F54_SENSOR_SPEED:
- case F54_AMP_FULL_RAW_CAP:
- case F54_AMP_RAW_ADC:
- f54->report_size = 2 * tx * rx;
- break;
- case F54_HIGH_RESISTANCE:
- f54->report_size = HIGH_RESISTANCE_DATA_SIZE;
- break;
- case F54_TX_TO_TX_SHORTS:
- case F54_TX_OPENS:
- case F54_TX_TO_GND_SHORTS:
- f54->report_size = (tx + 7) / 8;
- break;
- case F54_RX_TO_RX_SHORTS_1:
- case F54_RX_OPENS_1:
- if (rx < tx)
- f54->report_size = 2 * rx * rx;
- else
- f54->report_size = 2 * tx * rx;
- break;
- case F54_FULL_RAW_CAP_MIN_MAX:
- f54->report_size = FULL_RAW_CAP_MIN_MAX_DATA_SIZE;
- break;
- case F54_RX_TO_RX_SHORTS_2:
- case F54_RX_OPENS_2:
- if (rx <= tx)
- f54->report_size = 0;
- else
- f54->report_size = 2 * rx * (rx - tx);
- break;
- case F54_ADC_RANGE:
- if (f54->query.has_signal_clarity) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->control.reg_41->address,
- f54->control.reg_41->data,
- sizeof(f54->control.reg_41->data));
- if (retval < 0) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Failed to read control reg_41\n",
- __func__);
- f54->report_size = 0;
- break;
- }
- if (!f54->control.reg_41->no_signal_clarity) {
- if (tx % 4)
- tx += 4 - (tx % 4);
- }
- }
- f54->report_size = 2 * tx * rx;
- break;
- case F54_TRX_OPENS:
- case F54_TRX_TO_GND_SHORTS:
- case F54_TRX_SHORTS:
- f54->report_size = TRX_OPEN_SHORT_DATA_SIZE;
- break;
- case F54_ABS_RAW_CAP:
- case F54_ABS_DELTA_CAP:
- case F54_ABS_HYBRID_DELTA_CAP:
- case F54_ABS_HYBRID_RAW_CAP:
- f54->report_size = 4 * (tx + rx);
- break;
- default:
- f54->report_size = 0;
- }
-
- return;
-}
-
-static int test_set_interrupt(bool set)
-{
- int retval;
- unsigned char ii;
- unsigned char zero = 0x00;
- unsigned char *intr_mask;
- unsigned short f01_ctrl_reg;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- intr_mask = rmi4_data->intr_mask;
- f01_ctrl_reg = rmi4_data->f01_ctrl_base_addr + 1 + f54->intr_reg_num;
-
- if (!set) {
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f01_ctrl_reg,
- &zero,
- sizeof(zero));
- if (retval < 0)
- return retval;
- }
-
- for (ii = 0; ii < rmi4_data->num_of_intr_regs; ii++) {
- if (intr_mask[ii] != 0x00) {
- f01_ctrl_reg = rmi4_data->f01_ctrl_base_addr + 1 + ii;
- if (set) {
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f01_ctrl_reg,
- &zero,
- sizeof(zero));
- if (retval < 0)
- return retval;
- } else {
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f01_ctrl_reg,
- &(intr_mask[ii]),
- sizeof(intr_mask[ii]));
- if (retval < 0)
- return retval;
- }
- }
- }
-
- f01_ctrl_reg = rmi4_data->f01_ctrl_base_addr + 1 + f54->intr_reg_num;
-
- if (set) {
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f01_ctrl_reg,
- &f54->intr_mask,
- 1);
- if (retval < 0)
- return retval;
- }
-
- return 0;
-}
-
-static int test_wait_for_command_completion(void)
-{
- int retval;
- unsigned char value;
- unsigned char timeout_count;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- timeout_count = 0;
- do {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->command_base_addr,
- &value,
- sizeof(value));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read command register\n",
- __func__);
- return retval;
- }
-
- if (value == 0x00)
- break;
-
- msleep(100);
- timeout_count++;
- } while (timeout_count < COMMAND_TIMEOUT_100MS);
-
- if (timeout_count == COMMAND_TIMEOUT_100MS) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Timed out waiting for command completion\n",
- __func__);
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int test_do_command(unsigned char command)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f54->command_base_addr,
- &command,
- sizeof(command));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write command\n",
- __func__);
- return retval;
- }
-
- retval = test_wait_for_command_completion();
- if (retval < 0)
- return retval;
-
- return 0;
-}
-
-static int test_do_preparation(void)
-{
- int retval;
- unsigned char value;
- unsigned char zero = 0x00;
- unsigned char device_ctrl;
- struct f54_control_86 reg_86;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_ctrl_base_addr,
- &device_ctrl,
- sizeof(device_ctrl));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set no sleep\n",
- __func__);
- return retval;
- }
-
- device_ctrl |= NO_SLEEP_ON;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- rmi4_data->f01_ctrl_base_addr,
- &device_ctrl,
- sizeof(device_ctrl));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set no sleep\n",
- __func__);
- return retval;
- }
-
- if ((f54->query.has_query13) &&
- (f54->query_13.has_ctrl86)) {
- reg_86.data[0] = f54->control.reg_86->data[0];
- reg_86.dynamic_sense_display_ratio = 1;
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f54->control.reg_86->address,
- reg_86.data,
- sizeof(reg_86.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set sense display ratio\n",
- __func__);
- return retval;
- }
- }
-
- if (f54->skip_preparation)
- return 0;
-
- switch (f54->report_type) {
- case F54_16BIT_IMAGE:
- case F54_RAW_16BIT_IMAGE:
- case F54_SENSOR_SPEED:
- case F54_ADC_RANGE:
- case F54_ABS_RAW_CAP:
- case F54_ABS_DELTA_CAP:
- case F54_ABS_HYBRID_DELTA_CAP:
- case F54_ABS_HYBRID_RAW_CAP:
- break;
- case F54_AMP_RAW_ADC:
- if (f54->query_49.has_ctrl188) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->control.reg_188->address,
- f54->control.reg_188->data,
- sizeof(f54->control.reg_188->data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set start production test\n",
- __func__);
- return retval;
- }
- f54->control.reg_188->start_production_test = 1;
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f54->control.reg_188->address,
- f54->control.reg_188->data,
- sizeof(f54->control.reg_188->data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set start production test\n",
- __func__);
- return retval;
- }
- }
- break;
- default:
- if (f54->query.touch_controller_family == 1)
- disable_cbc(reg_7);
- else if (f54->query.has_ctrl88)
- disable_cbc(reg_88);
-
- if (f54->query.has_0d_acquisition_control)
- disable_cbc(reg_57);
-
- if ((f54->query.has_query15) &&
- (f54->query_15.has_query25) &&
- (f54->query_25.has_query27) &&
- (f54->query_27.has_query29) &&
- (f54->query_29.has_query30) &&
- (f54->query_30.has_query32) &&
- (f54->query_32.has_query33) &&
- (f54->query_33.has_query36) &&
- (f54->query_36.has_query38) &&
- (f54->query_38.has_ctrl149)) {
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f54->control.reg_149->address,
- &zero,
- sizeof(f54->control.reg_149->data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to disable global CBC\n",
- __func__);
- return retval;
- }
- }
-
- if (f54->query.has_signal_clarity) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->control.reg_41->address,
- &value,
- sizeof(f54->control.reg_41->data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to disable signal clarity\n",
- __func__);
- return retval;
- }
- value |= 0x01;
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f54->control.reg_41->address,
- &value,
- sizeof(f54->control.reg_41->data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to disable signal clarity\n",
- __func__);
- return retval;
- }
- }
-
- retval = test_do_command(COMMAND_FORCE_UPDATE);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to do force update\n",
- __func__);
- return retval;
- }
-
- retval = test_do_command(COMMAND_FORCE_CAL);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to do force cal\n",
- __func__);
- return retval;
- }
- }
-
- return 0;
-}
-
-static int test_do_afe_calibration(enum f54_afe_cal mode)
-{
- int retval;
- unsigned char timeout = CALIBRATION_TIMEOUT_S;
- unsigned char timeout_count = 0;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->control.reg_188->address,
- f54->control.reg_188->data,
- sizeof(f54->control.reg_188->data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to start calibration\n",
- __func__);
- return retval;
- }
-
- if (mode == F54_AFE_CAL)
- f54->control.reg_188->start_calibration = 1;
- else if (mode == F54_AFE_IS_CAL)
- f54->control.reg_188->start_is_calibration = 1;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f54->control.reg_188->address,
- f54->control.reg_188->data,
- sizeof(f54->control.reg_188->data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to start calibration\n",
- __func__);
- return retval;
- }
-
- do {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->control.reg_188->address,
- f54->control.reg_188->data,
- sizeof(f54->control.reg_188->data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to complete calibration\n",
- __func__);
- return retval;
- }
-
- if (mode == F54_AFE_CAL) {
- if (!f54->control.reg_188->start_calibration)
- break;
- } else if (mode == F54_AFE_IS_CAL) {
- if (!f54->control.reg_188->start_is_calibration)
- break;
- }
-
- if (timeout_count == timeout) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Timed out waiting for calibration completion\n",
- __func__);
- return -EBUSY;
- }
-
- timeout_count++;
- msleep(1000);
- } while (true);
-
- /* check CRC */
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->data_31.address,
- f54->data_31.data,
- sizeof(f54->data_31.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read calibration CRC\n",
- __func__);
- return retval;
- }
-
- if (mode == F54_AFE_CAL) {
- if (f54->data_31.calibration_crc == 0)
- return 0;
- } else if (mode == F54_AFE_IS_CAL) {
- if (f54->data_31.is_calibration_crc == 0)
- return 0;
- }
-
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read calibration CRC\n",
- __func__);
-
- return -EINVAL;
-}
-
-static int test_check_for_idle_status(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- switch (f54->status) {
- case STATUS_IDLE:
- retval = 0;
- break;
- case STATUS_BUSY:
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Status busy\n",
- __func__);
- retval = -EINVAL;
- break;
- case STATUS_ERROR:
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Status error\n",
- __func__);
- retval = -EINVAL;
- break;
- default:
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Invalid status (%d)\n",
- __func__, f54->status);
- retval = -EINVAL;
- }
-
- return retval;
-}
-
-static void test_timeout_work(struct work_struct *work)
-{
- int retval;
- unsigned char command;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- mutex_lock(&f54->status_mutex);
-
- if (f54->status == STATUS_BUSY) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->command_base_addr,
- &command,
- sizeof(command));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read command register\n",
- __func__);
- } else if (command & COMMAND_GET_REPORT) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Report type not supported by FW\n",
- __func__);
- } else {
- queue_work(f54->test_report_workqueue,
- &f54->test_report_work);
- goto exit;
- }
- f54->status = STATUS_ERROR;
- f54->report_size = 0;
- }
-
-exit:
- mutex_unlock(&f54->status_mutex);
-
- return;
-}
-
-static enum hrtimer_restart test_get_report_timeout(struct hrtimer *timer)
-{
- schedule_work(&(f54->timeout_work));
-
- return HRTIMER_NORESTART;
-}
-
-static ssize_t test_sysfs_num_of_mapped_tx_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", f54->tx_assigned);
-}
-
-static ssize_t test_sysfs_num_of_mapped_rx_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", f54->rx_assigned);
-}
-
-static ssize_t test_sysfs_tx_mapping_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int cnt;
- int count = 0;
- unsigned char ii;
- unsigned char tx_num;
- unsigned char tx_electrodes = f54->query.num_of_tx_electrodes;
-
- if (!f55)
- return -EINVAL;
-
- for (ii = 0; ii < tx_electrodes; ii++) {
- tx_num = f55->tx_assignment[ii];
- if (tx_num == 0xff)
- cnt = snprintf(buf, PAGE_SIZE - count, "xx ");
- else
- cnt = snprintf(buf, PAGE_SIZE - count, "%02u ", tx_num);
- buf += cnt;
- count += cnt;
- }
-
- snprintf(buf, PAGE_SIZE - count, "\n");
- count++;
-
- return count;
-}
-
-static ssize_t test_sysfs_rx_mapping_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int cnt;
- int count = 0;
- unsigned char ii;
- unsigned char rx_num;
- unsigned char rx_electrodes = f54->query.num_of_rx_electrodes;
-
- if (!f55)
- return -EINVAL;
-
- for (ii = 0; ii < rx_electrodes; ii++) {
- rx_num = f55->rx_assignment[ii];
- if (rx_num == 0xff)
- cnt = snprintf(buf, PAGE_SIZE - count, "xx ");
- else
- cnt = snprintf(buf, PAGE_SIZE - count, "%02u ", rx_num);
- buf += cnt;
- count += cnt;
- }
-
- snprintf(buf, PAGE_SIZE - count, "\n");
- count++;
-
- return count;
-}
-
-static ssize_t test_sysfs_report_size_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", f54->report_size);
-}
-
-static ssize_t test_sysfs_status_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int retval;
-
- mutex_lock(&f54->status_mutex);
-
- retval = snprintf(buf, PAGE_SIZE, "%u\n", f54->status);
-
- mutex_unlock(&f54->status_mutex);
-
- return retval;
-}
-
-static ssize_t test_sysfs_do_preparation_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long setting;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = sstrtoul(buf, 10, &setting);
- if (retval)
- return retval;
-
- if (setting != 1)
- return -EINVAL;
-
- mutex_lock(&f54->status_mutex);
-
- retval = test_check_for_idle_status();
- if (retval < 0)
- goto exit;
-
- retval = test_do_preparation();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to do preparation\n",
- __func__);
- goto exit;
- }
-
- retval = count;
-
-exit:
- mutex_unlock(&f54->status_mutex);
-
- return retval;
-}
-
-static ssize_t test_sysfs_force_cal_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long setting;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = sstrtoul(buf, 10, &setting);
- if (retval)
- return retval;
-
- if (setting != 1)
- return -EINVAL;
-
- mutex_lock(&f54->status_mutex);
-
- retval = test_check_for_idle_status();
- if (retval < 0)
- goto exit;
-
- retval = test_do_command(COMMAND_FORCE_CAL);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to do force cal\n",
- __func__);
- goto exit;
- }
-
- retval = count;
-
-exit:
- mutex_unlock(&f54->status_mutex);
-
- return retval;
-}
-
-static ssize_t test_sysfs_get_report_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned char command;
- unsigned long setting;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = sstrtoul(buf, 10, &setting);
- if (retval)
- return retval;
-
- if (setting != 1)
- return -EINVAL;
-
- mutex_lock(&f54->status_mutex);
-
- retval = test_check_for_idle_status();
- if (retval < 0)
- goto exit;
-
- if (!test_report_type_valid(f54->report_type)) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Invalid report type\n",
- __func__);
- retval = -EINVAL;
- goto exit;
- }
-
- test_set_interrupt(true);
-
- command = (unsigned char)COMMAND_GET_REPORT;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f54->command_base_addr,
- &command,
- sizeof(command));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write get report command\n",
- __func__);
- goto exit;
- }
-
- f54->status = STATUS_BUSY;
- f54->report_size = 0;
- f54->data_pos = 0;
-
- hrtimer_start(&f54->watchdog,
- ktime_set(GET_REPORT_TIMEOUT_S, 0),
- HRTIMER_MODE_REL);
-
- retval = count;
-
-exit:
- mutex_unlock(&f54->status_mutex);
-
- return retval;
-}
-
-static ssize_t test_sysfs_resume_touch_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned char device_ctrl;
- unsigned long setting;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = sstrtoul(buf, 10, &setting);
- if (retval)
- return retval;
-
- if (setting != 1)
- return -EINVAL;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- rmi4_data->f01_ctrl_base_addr,
- &device_ctrl,
- sizeof(device_ctrl));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to restore no sleep setting\n",
- __func__);
- return retval;
- }
-
- device_ctrl = device_ctrl & ~NO_SLEEP_ON;
- device_ctrl |= rmi4_data->no_sleep_setting;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- rmi4_data->f01_ctrl_base_addr,
- &device_ctrl,
- sizeof(device_ctrl));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to restore no sleep setting\n",
- __func__);
- return retval;
- }
-
- if ((f54->query.has_query13) &&
- (f54->query_13.has_ctrl86)) {
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f54->control.reg_86->address,
- f54->control.reg_86->data,
- sizeof(f54->control.reg_86->data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to restore sense display ratio\n",
- __func__);
- return retval;
- }
- }
-
- test_set_interrupt(false);
-
- if (f54->skip_preparation)
- return count;
-
- switch (f54->report_type) {
- case F54_16BIT_IMAGE:
- case F54_RAW_16BIT_IMAGE:
- case F54_SENSOR_SPEED:
- case F54_ADC_RANGE:
- case F54_ABS_RAW_CAP:
- case F54_ABS_DELTA_CAP:
- case F54_ABS_HYBRID_DELTA_CAP:
- case F54_ABS_HYBRID_RAW_CAP:
- break;
- case F54_AMP_RAW_ADC:
- if (f54->query_49.has_ctrl188) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->control.reg_188->address,
- f54->control.reg_188->data,
- sizeof(f54->control.reg_188->data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set start production test\n",
- __func__);
- return retval;
- }
- f54->control.reg_188->start_production_test = 0;
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f54->control.reg_188->address,
- f54->control.reg_188->data,
- sizeof(f54->control.reg_188->data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set start production test\n",
- __func__);
- return retval;
- }
- }
- break;
- default:
- rmi4_data->reset_device(rmi4_data, false);
- }
-
- return count;
-}
-
-static ssize_t test_sysfs_do_afe_calibration_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned long setting;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = sstrtoul(buf, 10, &setting);
- if (retval)
- return retval;
-
- if (!f54->query_49.has_ctrl188) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: F54_ANALOG_Ctrl188 not found\n",
- __func__);
- return -EINVAL;
- }
-
- if (setting == 0 || setting == 1)
- retval = test_do_afe_calibration((enum f54_afe_cal)setting);
- else
- return -EINVAL;
-
- if (retval)
- return retval;
- else
- return count;
-}
-
-static ssize_t test_sysfs_report_type_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", f54->report_type);
-}
-
-static ssize_t test_sysfs_report_type_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned char data;
- unsigned long setting;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = sstrtoul(buf, 10, &setting);
- if (retval)
- return retval;
-
- mutex_lock(&f54->status_mutex);
-
- retval = test_check_for_idle_status();
- if (retval < 0)
- goto exit;
-
- if (!test_report_type_valid((enum f54_report_types)setting)) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Report type not supported by driver\n",
- __func__);
- retval = -EINVAL;
- goto exit;
- }
-
- f54->report_type = (enum f54_report_types)setting;
- data = (unsigned char)setting;
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f54->data_base_addr,
- &data,
- sizeof(data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write report type\n",
- __func__);
- goto exit;
- }
-
- retval = count;
-
-exit:
- mutex_unlock(&f54->status_mutex);
-
- return retval;
-}
-
-static ssize_t test_sysfs_fifoindex_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int retval;
- unsigned char data[2];
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->data_base_addr + REPORT_INDEX_OFFSET,
- data,
- sizeof(data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read report index\n",
- __func__);
- return retval;
- }
-
- batohs(&f54->fifoindex, data);
-
- return snprintf(buf, PAGE_SIZE, "%u\n", f54->fifoindex);
-}
-
-static ssize_t test_sysfs_fifoindex_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned char data[2];
- unsigned long setting;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = sstrtoul(buf, 10, &setting);
- if (retval)
- return retval;
-
- f54->fifoindex = setting;
-
- hstoba(data, (unsigned short)setting);
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f54->data_base_addr + REPORT_INDEX_OFFSET,
- data,
- sizeof(data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write report index\n",
- __func__);
- return retval;
- }
-
- return count;
-}
-
-static ssize_t test_sysfs_no_auto_cal_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return snprintf(buf, PAGE_SIZE, "%u\n", f54->no_auto_cal);
-}
-
-static ssize_t test_sysfs_no_auto_cal_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned char data;
- unsigned long setting;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = sstrtoul(buf, 10, &setting);
- if (retval)
- return retval;
-
- if (setting > 1)
- return -EINVAL;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->control_base_addr,
- &data,
- sizeof(data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read no auto cal setting\n",
- __func__);
- return retval;
- }
-
- if (setting)
- data |= CONTROL_NO_AUTO_CAL;
- else
- data &= ~CONTROL_NO_AUTO_CAL;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f54->control_base_addr,
- &data,
- sizeof(data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write no auto cal setting\n",
- __func__);
- return retval;
- }
-
- f54->no_auto_cal = (setting == 1);
-
- return count;
-}
-
-static ssize_t test_sysfs_read_report_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- unsigned int ii;
- unsigned int jj;
- int cnt;
- int count = 0;
- int tx_num = f54->tx_assigned;
- int rx_num = f54->rx_assigned;
- char *report_data_8;
- short *report_data_16;
- int *report_data_32;
- unsigned short *report_data_u16;
- unsigned int *report_data_u32;
-
- switch (f54->report_type) {
- case F54_8BIT_IMAGE:
- report_data_8 = (char *)f54->report_data;
- for (ii = 0; ii < f54->report_size; ii++) {
- cnt = snprintf(buf, PAGE_SIZE - count, "%03d: %d\n",
- ii, *report_data_8);
- report_data_8++;
- buf += cnt;
- count += cnt;
- }
- break;
- case F54_AMP_RAW_ADC:
- report_data_u16 = (unsigned short *)f54->report_data;
- cnt = snprintf(buf, PAGE_SIZE - count, "tx = %d\nrx = %d\n",
- tx_num, rx_num);
- buf += cnt;
- count += cnt;
-
- for (ii = 0; ii < tx_num; ii++) {
- for (jj = 0; jj < (rx_num - 1); jj++) {
- cnt = snprintf(buf, PAGE_SIZE - count, "%-4d ",
- *report_data_u16);
- report_data_u16++;
- buf += cnt;
- count += cnt;
- }
- cnt = snprintf(buf, PAGE_SIZE - count, "%-4d\n",
- *report_data_u16);
- report_data_u16++;
- buf += cnt;
- count += cnt;
- }
- break;
- case F54_16BIT_IMAGE:
- case F54_RAW_16BIT_IMAGE:
- case F54_TRUE_BASELINE:
- case F54_FULL_RAW_CAP:
- case F54_FULL_RAW_CAP_NO_RX_COUPLING:
- case F54_SENSOR_SPEED:
- case F54_AMP_FULL_RAW_CAP:
- report_data_16 = (short *)f54->report_data;
- cnt = snprintf(buf, PAGE_SIZE - count, "tx = %d\nrx = %d\n",
- tx_num, rx_num);
- buf += cnt;
- count += cnt;
-
- for (ii = 0; ii < tx_num; ii++) {
- for (jj = 0; jj < (rx_num - 1); jj++) {
- cnt = snprintf(buf, PAGE_SIZE - count, "%-4d ",
- *report_data_16);
- report_data_16++;
- buf += cnt;
- count += cnt;
- }
- cnt = snprintf(buf, PAGE_SIZE - count, "%-4d\n",
- *report_data_16);
- report_data_16++;
- buf += cnt;
- count += cnt;
- }
- break;
- case F54_HIGH_RESISTANCE:
- case F54_FULL_RAW_CAP_MIN_MAX:
- report_data_16 = (short *)f54->report_data;
- for (ii = 0; ii < f54->report_size; ii += 2) {
- cnt = snprintf(buf, PAGE_SIZE - count, "%03d: %d\n",
- ii / 2, *report_data_16);
- report_data_16++;
- buf += cnt;
- count += cnt;
- }
- break;
- case F54_ABS_RAW_CAP:
- report_data_u32 = (unsigned int *)f54->report_data;
- cnt = snprintf(buf, PAGE_SIZE - count, "rx ");
- buf += cnt;
- count += cnt;
- for (ii = 0; ii < rx_num; ii++) {
- cnt = snprintf(buf, PAGE_SIZE - count, " %2d", ii);
- buf += cnt;
- count += cnt;
- }
- cnt = snprintf(buf, PAGE_SIZE - count, "\n");
- buf += cnt;
- count += cnt;
-
- cnt = snprintf(buf, PAGE_SIZE - count, " ");
- buf += cnt;
- count += cnt;
- for (ii = 0; ii < rx_num; ii++) {
- cnt = snprintf(buf, PAGE_SIZE - count, " %5u",
- *report_data_u32);
- report_data_u32++;
- buf += cnt;
- count += cnt;
- }
- cnt = snprintf(buf, PAGE_SIZE - count, "\n");
- buf += cnt;
- count += cnt;
-
- cnt = snprintf(buf, PAGE_SIZE - count, "tx ");
- buf += cnt;
- count += cnt;
- for (ii = 0; ii < tx_num; ii++) {
- cnt = snprintf(buf, PAGE_SIZE - count, " %2d", ii);
- buf += cnt;
- count += cnt;
- }
- cnt = snprintf(buf, PAGE_SIZE - count, "\n");
- buf += cnt;
- count += cnt;
-
- cnt = snprintf(buf, PAGE_SIZE - count, " ");
- buf += cnt;
- count += cnt;
- for (ii = 0; ii < tx_num; ii++) {
- cnt = snprintf(buf, PAGE_SIZE - count, " %5u",
- *report_data_u32);
- report_data_u32++;
- buf += cnt;
- count += cnt;
- }
- cnt = snprintf(buf, PAGE_SIZE - count, "\n");
- buf += cnt;
- count += cnt;
- break;
- case F54_ABS_DELTA_CAP:
- case F54_ABS_HYBRID_DELTA_CAP:
- case F54_ABS_HYBRID_RAW_CAP:
- report_data_32 = (int *)f54->report_data;
- cnt = snprintf(buf, PAGE_SIZE - count, "rx ");
- buf += cnt;
- count += cnt;
- for (ii = 0; ii < rx_num; ii++) {
- cnt = snprintf(buf, PAGE_SIZE - count, " %2d", ii);
- buf += cnt;
- count += cnt;
- }
- cnt = snprintf(buf, PAGE_SIZE - count, "\n");
- buf += cnt;
- count += cnt;
-
- cnt = snprintf(buf, PAGE_SIZE - count, " ");
- buf += cnt;
- count += cnt;
- for (ii = 0; ii < rx_num; ii++) {
- cnt = snprintf(buf, PAGE_SIZE - count, " %5d",
- *report_data_32);
- report_data_32++;
- buf += cnt;
- count += cnt;
- }
- cnt = snprintf(buf, PAGE_SIZE - count, "\n");
- buf += cnt;
- count += cnt;
-
- cnt = snprintf(buf, PAGE_SIZE - count, "tx ");
- buf += cnt;
- count += cnt;
- for (ii = 0; ii < tx_num; ii++) {
- cnt = snprintf(buf, PAGE_SIZE - count, " %2d", ii);
- buf += cnt;
- count += cnt;
- }
- cnt = snprintf(buf, PAGE_SIZE - count, "\n");
- buf += cnt;
- count += cnt;
-
- cnt = snprintf(buf, PAGE_SIZE - count, " ");
- buf += cnt;
- count += cnt;
- for (ii = 0; ii < tx_num; ii++) {
- cnt = snprintf(buf, PAGE_SIZE - count, " %5d",
- *report_data_32);
- report_data_32++;
- buf += cnt;
- count += cnt;
- }
- cnt = snprintf(buf, PAGE_SIZE - count, "\n");
- buf += cnt;
- count += cnt;
- break;
- default:
- for (ii = 0; ii < f54->report_size; ii++) {
- cnt = snprintf(buf, PAGE_SIZE - count, "%03d: 0x%02x\n",
- ii, f54->report_data[ii]);
- buf += cnt;
- count += cnt;
- }
- }
-
- snprintf(buf, PAGE_SIZE - count, "\n");
- count++;
-
- return count;
-}
-
-static ssize_t test_sysfs_read_report_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned char timeout = GET_REPORT_TIMEOUT_S * 10;
- unsigned char timeout_count;
- const char cmd[] = {'1', 0};
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = test_sysfs_report_type_store(dev, attr, buf, count);
- if (retval < 0)
- goto exit;
-
- retval = test_sysfs_do_preparation_store(dev, attr, cmd, 1);
- if (retval < 0)
- goto exit;
-
- retval = test_sysfs_get_report_store(dev, attr, cmd, 1);
- if (retval < 0)
- goto exit;
-
- timeout_count = 0;
- do {
- if (f54->status != STATUS_BUSY)
- break;
- msleep(100);
- timeout_count++;
- } while (timeout_count < timeout);
-
- if ((f54->status != STATUS_IDLE) || (f54->report_size == 0)) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read report\n",
- __func__);
- retval = -EINVAL;
- goto exit;
- }
-
- retval = test_sysfs_resume_touch_store(dev, attr, cmd, 1);
- if (retval < 0)
- goto exit;
-
- return count;
-
-exit:
- rmi4_data->reset_device(rmi4_data, false);
-
- return retval;
-}
-
-static ssize_t test_sysfs_data_read(struct file *data_file,
- struct kobject *kobj, struct bin_attribute *attributes,
- char *buf, loff_t pos, size_t count)
-{
- int retval;
- unsigned int read_size;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- mutex_lock(&f54->status_mutex);
-
- retval = test_check_for_idle_status();
- if (retval < 0)
- goto exit;
-
- if (!f54->report_data) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Report type %d data not available\n",
- __func__, f54->report_type);
- retval = -EINVAL;
- goto exit;
- }
-
- if ((f54->data_pos + count) > f54->report_size)
- read_size = f54->report_size - f54->data_pos;
- else
- read_size = min_t(unsigned int, count, f54->report_size);
-
- retval = secure_memcpy(buf, count, f54->report_data + f54->data_pos,
- f54->data_buffer_size - f54->data_pos, read_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to copy report data\n",
- __func__);
- goto exit;
- }
- f54->data_pos += read_size;
- retval = read_size;
-
-exit:
- mutex_unlock(&f54->status_mutex);
-
- return retval;
-}
-
-static void test_report_work(struct work_struct *work)
-{
- int retval;
- unsigned char report_index[2];
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- mutex_lock(&f54->status_mutex);
-
- if (f54->status != STATUS_BUSY) {
- retval = STATUS_ERROR;
- goto exit;
- }
-
- retval = test_wait_for_command_completion();
- if (retval < 0) {
- retval = STATUS_ERROR;
- goto exit;
- }
-
- test_set_report_size();
- if (f54->report_size == 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Report data size = 0\n",
- __func__);
- retval = STATUS_ERROR;
- goto exit;
- }
-
- if (f54->data_buffer_size < f54->report_size) {
- if (f54->data_buffer_size)
- kfree(f54->report_data);
- f54->report_data = kzalloc(f54->report_size, GFP_KERNEL);
- if (!f54->report_data) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for data buffer\n",
- __func__);
- f54->data_buffer_size = 0;
- retval = STATUS_ERROR;
- goto exit;
- }
- f54->data_buffer_size = f54->report_size;
- }
-
- report_index[0] = 0;
- report_index[1] = 0;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- f54->data_base_addr + REPORT_INDEX_OFFSET,
- report_index,
- sizeof(report_index));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to write report data index\n",
- __func__);
- retval = STATUS_ERROR;
- goto exit;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->data_base_addr + REPORT_DATA_OFFSET,
- f54->report_data,
- f54->report_size);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read report data\n",
- __func__);
- retval = STATUS_ERROR;
- goto exit;
- }
-
- retval = STATUS_IDLE;
-
-exit:
- mutex_unlock(&f54->status_mutex);
-
- if (retval == STATUS_ERROR)
- f54->report_size = 0;
-
- f54->status = retval;
-
- return;
-}
-
-static void test_remove_sysfs(void)
-{
- sysfs_remove_group(f54->sysfs_dir, &attr_group);
- sysfs_remove_bin_file(f54->sysfs_dir, &test_report_data);
- kobject_put(f54->sysfs_dir);
-
- return;
-}
-
-static int test_set_sysfs(void)
-{
- int retval;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- f54->sysfs_dir = kobject_create_and_add(SYSFS_FOLDER_NAME,
- &rmi4_data->input_dev->dev.kobj);
- if (!f54->sysfs_dir) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs directory\n",
- __func__);
- goto exit_directory;
- }
-
- retval = sysfs_create_bin_file(f54->sysfs_dir, &test_report_data);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs bin file\n",
- __func__);
- goto exit_bin_file;
- }
-
- retval = sysfs_create_group(f54->sysfs_dir, &attr_group);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs attributes\n",
- __func__);
- goto exit_attributes;
- }
-
- return 0;
-
-exit_attributes:
- sysfs_remove_group(f54->sysfs_dir, &attr_group);
- sysfs_remove_bin_file(f54->sysfs_dir, &test_report_data);
-
-exit_bin_file:
- kobject_put(f54->sysfs_dir);
-
-exit_directory:
- return -ENODEV;
-}
-
-static void test_free_control_mem(void)
-{
- struct f54_control control = f54->control;
-
- kfree(control.reg_7);
- kfree(control.reg_41);
- kfree(control.reg_57);
- kfree(control.reg_86);
- kfree(control.reg_88);
- kfree(control.reg_110);
- kfree(control.reg_149);
- kfree(control.reg_188);
-
- return;
-}
-
-static void test_set_data(void)
-{
- unsigned short reg_addr;
-
- reg_addr = f54->data_base_addr + REPORT_DATA_OFFSET + 1;
-
- /* data 4 */
- if (f54->query.has_sense_frequency_control)
- reg_addr++;
-
- /* data 5 reserved */
-
- /* data 6 */
- if (f54->query.has_interference_metric)
- reg_addr += 2;
-
- /* data 7 */
- if (f54->query.has_one_byte_report_rate |
- f54->query.has_two_byte_report_rate)
- reg_addr++;
- if (f54->query.has_two_byte_report_rate)
- reg_addr++;
-
- /* data 8 */
- if (f54->query.has_variance_metric)
- reg_addr += 2;
-
- /* data 9 */
- if (f54->query.has_multi_metric_state_machine)
- reg_addr += 2;
-
- /* data 10 */
- if (f54->query.has_multi_metric_state_machine |
- f54->query.has_noise_state)
- reg_addr++;
-
- /* data 11 */
- if (f54->query.has_status)
- reg_addr++;
-
- /* data 12 */
- if (f54->query.has_slew_metric)
- reg_addr += 2;
-
- /* data 13 */
- if (f54->query.has_multi_metric_state_machine)
- reg_addr += 2;
-
- /* data 14 */
- if (f54->query_13.has_cidim)
- reg_addr++;
-
- /* data 15 */
- if (f54->query_13.has_rail_im)
- reg_addr++;
-
- /* data 16 */
- if (f54->query_13.has_noise_mitigation_enhancement)
- reg_addr++;
-
- /* data 17 */
- if (f54->query_16.has_data17)
- reg_addr++;
-
- /* data 18 */
- if (f54->query_21.has_query24_data18)
- reg_addr++;
-
- /* data 19 */
- if (f54->query_21.has_data19)
- reg_addr++;
-
- /* data_20 */
- if (f54->query_25.has_ctrl109)
- reg_addr++;
-
- /* data 21 */
- if (f54->query_27.has_data21)
- reg_addr++;
-
- /* data 22 */
- if (f54->query_27.has_data22)
- reg_addr++;
-
- /* data 23 */
- if (f54->query_29.has_data23)
- reg_addr++;
-
- /* data 24 */
- if (f54->query_32.has_data24)
- reg_addr++;
-
- /* data 25 */
- if (f54->query_35.has_data25)
- reg_addr++;
-
- /* data 26 */
- if (f54->query_35.has_data26)
- reg_addr++;
-
- /* data 27 */
- if (f54->query_46.has_data27)
- reg_addr++;
-
- /* data 28 */
- if (f54->query_46.has_data28)
- reg_addr++;
-
- /* data 29 30 reserved */
-
- /* data 31 */
- if (f54->query_49.has_data31) {
- f54->data_31.address = reg_addr;
- reg_addr++;
- }
-
- return;
-}
-
-static int test_set_controls(void)
-{
- int retval;
- unsigned char length;
- unsigned char num_of_sensing_freqs;
- unsigned short reg_addr = f54->control_base_addr;
- struct f54_control *control = &f54->control;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- num_of_sensing_freqs = f54->query.number_of_sensing_frequencies;
-
- /* control 0 */
- reg_addr += CONTROL_0_SIZE;
-
- /* control 1 */
- if ((f54->query.touch_controller_family == 0) ||
- (f54->query.touch_controller_family == 1))
- reg_addr += CONTROL_1_SIZE;
-
- /* control 2 */
- reg_addr += CONTROL_2_SIZE;
-
- /* control 3 */
- if (f54->query.has_pixel_touch_threshold_adjustment)
- reg_addr += CONTROL_3_SIZE;
-
- /* controls 4 5 6 */
- if ((f54->query.touch_controller_family == 0) ||
- (f54->query.touch_controller_family == 1))
- reg_addr += CONTROL_4_6_SIZE;
-
- /* control 7 */
- if (f54->query.touch_controller_family == 1) {
- control->reg_7 = kzalloc(sizeof(*(control->reg_7)),
- GFP_KERNEL);
- if (!control->reg_7)
- goto exit_no_mem;
- control->reg_7->address = reg_addr;
- reg_addr += CONTROL_7_SIZE;
- }
-
- /* controls 8 9 */
- if ((f54->query.touch_controller_family == 0) ||
- (f54->query.touch_controller_family == 1))
- reg_addr += CONTROL_8_9_SIZE;
-
- /* control 10 */
- if (f54->query.has_interference_metric)
- reg_addr += CONTROL_10_SIZE;
-
- /* control 11 */
- if (f54->query.has_ctrl11)
- reg_addr += CONTROL_11_SIZE;
-
- /* controls 12 13 */
- if (f54->query.has_relaxation_control)
- reg_addr += CONTROL_12_13_SIZE;
-
- /* controls 14 15 16 */
- if (f54->query.has_sensor_assignment) {
- reg_addr += CONTROL_14_SIZE;
- reg_addr += CONTROL_15_SIZE * f54->query.num_of_rx_electrodes;
- reg_addr += CONTROL_16_SIZE * f54->query.num_of_tx_electrodes;
- }
-
- /* controls 17 18 19 */
- if (f54->query.has_sense_frequency_control) {
- reg_addr += CONTROL_17_SIZE * num_of_sensing_freqs;
- reg_addr += CONTROL_18_SIZE * num_of_sensing_freqs;
- reg_addr += CONTROL_19_SIZE * num_of_sensing_freqs;
- }
-
- /* control 20 */
- reg_addr += CONTROL_20_SIZE;
-
- /* control 21 */
- if (f54->query.has_sense_frequency_control)
- reg_addr += CONTROL_21_SIZE;
-
- /* controls 22 23 24 25 26 */
- if (f54->query.has_firmware_noise_mitigation)
- reg_addr += CONTROL_22_26_SIZE;
-
- /* control 27 */
- if (f54->query.has_iir_filter)
- reg_addr += CONTROL_27_SIZE;
-
- /* control 28 */
- if (f54->query.has_firmware_noise_mitigation)
- reg_addr += CONTROL_28_SIZE;
-
- /* control 29 */
- if (f54->query.has_cmn_removal)
- reg_addr += CONTROL_29_SIZE;
-
- /* control 30 */
- if (f54->query.has_cmn_maximum)
- reg_addr += CONTROL_30_SIZE;
-
- /* control 31 */
- if (f54->query.has_touch_hysteresis)
- reg_addr += CONTROL_31_SIZE;
-
- /* controls 32 33 34 35 */
- if (f54->query.has_edge_compensation)
- reg_addr += CONTROL_32_35_SIZE;
-
- /* control 36 */
- if ((f54->query.curve_compensation_mode == 1) ||
- (f54->query.curve_compensation_mode == 2)) {
- if (f54->query.curve_compensation_mode == 1) {
- length = max(f54->query.num_of_rx_electrodes,
- f54->query.num_of_tx_electrodes);
- } else if (f54->query.curve_compensation_mode == 2) {
- length = f54->query.num_of_rx_electrodes;
- }
- reg_addr += CONTROL_36_SIZE * length;
- }
-
- /* control 37 */
- if (f54->query.curve_compensation_mode == 2)
- reg_addr += CONTROL_37_SIZE * f54->query.num_of_tx_electrodes;
-
- /* controls 38 39 40 */
- if (f54->query.has_per_frequency_noise_control) {
- reg_addr += CONTROL_38_SIZE * num_of_sensing_freqs;
- reg_addr += CONTROL_39_SIZE * num_of_sensing_freqs;
- reg_addr += CONTROL_40_SIZE * num_of_sensing_freqs;
- }
-
- /* control 41 */
- if (f54->query.has_signal_clarity) {
- control->reg_41 = kzalloc(sizeof(*(control->reg_41)),
- GFP_KERNEL);
- if (!control->reg_41)
- goto exit_no_mem;
- control->reg_41->address = reg_addr;
- reg_addr += CONTROL_41_SIZE;
- }
-
- /* control 42 */
- if (f54->query.has_variance_metric)
- reg_addr += CONTROL_42_SIZE;
-
- /* controls 43 44 45 46 47 48 49 50 51 52 53 54 */
- if (f54->query.has_multi_metric_state_machine)
- reg_addr += CONTROL_43_54_SIZE;
-
- /* controls 55 56 */
- if (f54->query.has_0d_relaxation_control)
- reg_addr += CONTROL_55_56_SIZE;
-
- /* control 57 */
- if (f54->query.has_0d_acquisition_control) {
- control->reg_57 = kzalloc(sizeof(*(control->reg_57)),
- GFP_KERNEL);
- if (!control->reg_57)
- goto exit_no_mem;
- control->reg_57->address = reg_addr;
- reg_addr += CONTROL_57_SIZE;
- }
-
- /* control 58 */
- if (f54->query.has_0d_acquisition_control)
- reg_addr += CONTROL_58_SIZE;
-
- /* control 59 */
- if (f54->query.has_h_blank)
- reg_addr += CONTROL_59_SIZE;
-
- /* controls 60 61 62 */
- if ((f54->query.has_h_blank) ||
- (f54->query.has_v_blank) ||
- (f54->query.has_long_h_blank))
- reg_addr += CONTROL_60_62_SIZE;
-
- /* control 63 */
- if ((f54->query.has_h_blank) ||
- (f54->query.has_v_blank) ||
- (f54->query.has_long_h_blank) ||
- (f54->query.has_slew_metric) ||
- (f54->query.has_slew_option) ||
- (f54->query.has_noise_mitigation2))
- reg_addr += CONTROL_63_SIZE;
-
- /* controls 64 65 66 67 */
- if (f54->query.has_h_blank)
- reg_addr += CONTROL_64_67_SIZE * 7;
- else if ((f54->query.has_v_blank) ||
- (f54->query.has_long_h_blank))
- reg_addr += CONTROL_64_67_SIZE;
-
- /* controls 68 69 70 71 72 73 */
- if ((f54->query.has_h_blank) ||
- (f54->query.has_v_blank) ||
- (f54->query.has_long_h_blank))
- reg_addr += CONTROL_68_73_SIZE;
-
- /* control 74 */
- if (f54->query.has_slew_metric)
- reg_addr += CONTROL_74_SIZE;
-
- /* control 75 */
- if (f54->query.has_enhanced_stretch)
- reg_addr += CONTROL_75_SIZE * num_of_sensing_freqs;
-
- /* control 76 */
- if (f54->query.has_startup_fast_relaxation)
- reg_addr += CONTROL_76_SIZE;
-
- /* controls 77 78 */
- if (f54->query.has_esd_control)
- reg_addr += CONTROL_77_78_SIZE;
-
- /* controls 79 80 81 82 83 */
- if (f54->query.has_noise_mitigation2)
- reg_addr += CONTROL_79_83_SIZE;
-
- /* controls 84 85 */
- if (f54->query.has_energy_ratio_relaxation)
- reg_addr += CONTROL_84_85_SIZE;
-
- /* control 86 */
- if (f54->query_13.has_ctrl86) {
- control->reg_86 = kzalloc(sizeof(*(control->reg_86)),
- GFP_KERNEL);
- if (!control->reg_86)
- goto exit_no_mem;
- control->reg_86->address = reg_addr;
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->control.reg_86->address,
- f54->control.reg_86->data,
- sizeof(f54->control.reg_86->data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read sense display ratio\n",
- __func__);
- return retval;
- }
- reg_addr += CONTROL_86_SIZE;
- }
-
- /* control 87 */
- if (f54->query_13.has_ctrl87)
- reg_addr += CONTROL_87_SIZE;
-
- /* control 88 */
- if (f54->query.has_ctrl88) {
- control->reg_88 = kzalloc(sizeof(*(control->reg_88)),
- GFP_KERNEL);
- if (!control->reg_88)
- goto exit_no_mem;
- control->reg_88->address = reg_addr;
- reg_addr += CONTROL_88_SIZE;
- }
-
- /* control 89 */
- if (f54->query_13.has_cidim ||
- f54->query_13.has_noise_mitigation_enhancement ||
- f54->query_13.has_rail_im)
- reg_addr += CONTROL_89_SIZE;
-
- /* control 90 */
- if (f54->query_15.has_ctrl90)
- reg_addr += CONTROL_90_SIZE;
-
- /* control 91 */
- if (f54->query_21.has_ctrl91)
- reg_addr += CONTROL_91_SIZE;
-
- /* control 92 */
- if (f54->query_16.has_ctrl92)
- reg_addr += CONTROL_92_SIZE;
-
- /* control 93 */
- if (f54->query_16.has_ctrl93)
- reg_addr += CONTROL_93_SIZE;
-
- /* control 94 */
- if (f54->query_16.has_ctrl94_query18)
- reg_addr += CONTROL_94_SIZE;
-
- /* control 95 */
- if (f54->query_16.has_ctrl95_query19)
- reg_addr += CONTROL_95_SIZE;
-
- /* control 96 */
- if (f54->query_21.has_ctrl96)
- reg_addr += CONTROL_96_SIZE;
-
- /* control 97 */
- if (f54->query_21.has_ctrl97)
- reg_addr += CONTROL_97_SIZE;
-
- /* control 98 */
- if (f54->query_21.has_ctrl98)
- reg_addr += CONTROL_98_SIZE;
-
- /* control 99 */
- if (f54->query.touch_controller_family == 2)
- reg_addr += CONTROL_99_SIZE;
-
- /* control 100 */
- if (f54->query_16.has_ctrl100)
- reg_addr += CONTROL_100_SIZE;
-
- /* control 101 */
- if (f54->query_22.has_ctrl101)
- reg_addr += CONTROL_101_SIZE;
-
-
- /* control 102 */
- if (f54->query_23.has_ctrl102)
- reg_addr += CONTROL_102_SIZE;
-
- /* control 103 */
- if (f54->query_22.has_ctrl103_query26) {
- f54->skip_preparation = true;
- reg_addr += CONTROL_103_SIZE;
- }
-
- /* control 104 */
- if (f54->query_22.has_ctrl104)
- reg_addr += CONTROL_104_SIZE;
-
- /* control 105 */
- if (f54->query_22.has_ctrl105)
- reg_addr += CONTROL_105_SIZE;
-
- /* control 106 */
- if (f54->query_25.has_ctrl106)
- reg_addr += CONTROL_106_SIZE;
-
- /* control 107 */
- if (f54->query_25.has_ctrl107)
- reg_addr += CONTROL_107_SIZE;
-
- /* control 108 */
- if (f54->query_25.has_ctrl108)
- reg_addr += CONTROL_108_SIZE;
-
- /* control 109 */
- if (f54->query_25.has_ctrl109)
- reg_addr += CONTROL_109_SIZE;
-
- /* control 110 */
- if (f54->query_27.has_ctrl110) {
- control->reg_110 = kzalloc(sizeof(*(control->reg_110)),
- GFP_KERNEL);
- if (!control->reg_110)
- goto exit_no_mem;
- control->reg_110->address = reg_addr;
- reg_addr += CONTROL_110_SIZE;
- }
-
- /* control 111 */
- if (f54->query_27.has_ctrl111)
- reg_addr += CONTROL_111_SIZE;
-
- /* control 112 */
- if (f54->query_27.has_ctrl112)
- reg_addr += CONTROL_112_SIZE;
-
- /* control 113 */
- if (f54->query_27.has_ctrl113)
- reg_addr += CONTROL_113_SIZE;
-
- /* control 114 */
- if (f54->query_27.has_ctrl114)
- reg_addr += CONTROL_114_SIZE;
-
- /* control 115 */
- if (f54->query_29.has_ctrl115)
- reg_addr += CONTROL_115_SIZE;
-
- /* control 116 */
- if (f54->query_29.has_ctrl116)
- reg_addr += CONTROL_116_SIZE;
-
- /* control 117 */
- if (f54->query_29.has_ctrl117)
- reg_addr += CONTROL_117_SIZE;
-
- /* control 118 */
- if (f54->query_30.has_ctrl118)
- reg_addr += CONTROL_118_SIZE;
-
- /* control 119 */
- if (f54->query_30.has_ctrl119)
- reg_addr += CONTROL_119_SIZE;
-
- /* control 120 */
- if (f54->query_30.has_ctrl120)
- reg_addr += CONTROL_120_SIZE;
-
- /* control 121 */
- if (f54->query_30.has_ctrl121)
- reg_addr += CONTROL_121_SIZE;
-
- /* control 122 */
- if (f54->query_30.has_ctrl122_query31)
- reg_addr += CONTROL_122_SIZE;
-
- /* control 123 */
- if (f54->query_30.has_ctrl123)
- reg_addr += CONTROL_123_SIZE;
-
- /* control 124 reserved */
-
- /* control 125 */
- if (f54->query_32.has_ctrl125)
- reg_addr += CONTROL_125_SIZE;
-
- /* control 126 */
- if (f54->query_32.has_ctrl126)
- reg_addr += CONTROL_126_SIZE;
-
- /* control 127 */
- if (f54->query_32.has_ctrl127)
- reg_addr += CONTROL_127_SIZE;
-
- /* controls 128 129 130 131 reserved */
-
- /* control 132 */
- if (f54->query_33.has_ctrl132)
- reg_addr += CONTROL_132_SIZE;
-
- /* control 133 */
- if (f54->query_33.has_ctrl133)
- reg_addr += CONTROL_133_SIZE;
-
- /* control 134 */
- if (f54->query_33.has_ctrl134)
- reg_addr += CONTROL_134_SIZE;
-
- /* controls 135 136 reserved */
-
- /* control 137 */
- if (f54->query_35.has_ctrl137)
- reg_addr += CONTROL_137_SIZE;
-
- /* control 138 */
- if (f54->query_35.has_ctrl138)
- reg_addr += CONTROL_138_SIZE;
-
- /* control 139 */
- if (f54->query_35.has_ctrl139)
- reg_addr += CONTROL_139_SIZE;
-
- /* control 140 */
- if (f54->query_35.has_ctrl140)
- reg_addr += CONTROL_140_SIZE;
-
- /* control 141 reserved */
-
- /* control 142 */
- if (f54->query_36.has_ctrl142)
- reg_addr += CONTROL_142_SIZE;
-
- /* control 143 */
- if (f54->query_36.has_ctrl143)
- reg_addr += CONTROL_143_SIZE;
-
- /* control 144 */
- if (f54->query_36.has_ctrl144)
- reg_addr += CONTROL_144_SIZE;
-
- /* control 145 */
- if (f54->query_36.has_ctrl145)
- reg_addr += CONTROL_145_SIZE;
-
- /* control 146 */
- if (f54->query_36.has_ctrl146)
- reg_addr += CONTROL_146_SIZE;
-
- /* control 147 */
- if (f54->query_38.has_ctrl147)
- reg_addr += CONTROL_147_SIZE;
-
- /* control 148 */
- if (f54->query_38.has_ctrl148)
- reg_addr += CONTROL_148_SIZE;
-
- /* control 149 */
- if (f54->query_38.has_ctrl149) {
- control->reg_149 = kzalloc(sizeof(*(control->reg_149)),
- GFP_KERNEL);
- if (!control->reg_149)
- goto exit_no_mem;
- control->reg_149->address = reg_addr;
- reg_addr += CONTROL_149_SIZE;
- }
-
- /* controls 150 to 162 reserved */
-
- /* control 163 */
- if (f54->query_40.has_ctrl163_query41)
- reg_addr += CONTROL_163_SIZE;
-
- /* control 164 reserved */
-
- /* control 165 */
- if (f54->query_40.has_ctrl165_query42)
- reg_addr += CONTROL_165_SIZE;
-
- /* control 166 reserved */
-
- /* control 167 */
- if (f54->query_40.has_ctrl167)
- reg_addr += CONTROL_167_SIZE;
-
- /* controls 168 to 175 reserved */
-
- /* control 176 */
- if (f54->query_46.has_ctrl176)
- reg_addr += CONTROL_176_SIZE;
-
- /* controls 177 178 reserved */
-
- /* control 179 */
- if (f54->query_46.has_ctrl179)
- reg_addr += CONTROL_179_SIZE;
-
- /* controls 180 to 187 reserved */
-
- /* control 188 */
- if (f54->query_49.has_ctrl188) {
- control->reg_188 = kzalloc(sizeof(*(control->reg_188)),
- GFP_KERNEL);
- if (!control->reg_188)
- goto exit_no_mem;
- control->reg_188->address = reg_addr;
- reg_addr += CONTROL_188_SIZE;
- }
-
- return 0;
-
-exit_no_mem:
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for control registers\n",
- __func__);
- return -ENOMEM;
-}
-
-static int test_set_queries(void)
-{
- int retval;
- unsigned char offset;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr,
- f54->query.data,
- sizeof(f54->query.data));
- if (retval < 0)
- return retval;
-
- offset = sizeof(f54->query.data);
-
- /* query 12 */
- if (f54->query.has_sense_frequency_control == 0)
- offset -= 1;
-
- /* query 13 */
- if (f54->query.has_query13) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_13.data,
- sizeof(f54->query_13.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 14 */
- if (f54->query_13.has_ctrl87)
- offset += 1;
-
- /* query 15 */
- if (f54->query.has_query15) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_15.data,
- sizeof(f54->query_15.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 16 */
- if (f54->query_15.has_query16) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_16.data,
- sizeof(f54->query_16.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 17 */
- if (f54->query_16.has_query17)
- offset += 1;
-
- /* query 18 */
- if (f54->query_16.has_ctrl94_query18)
- offset += 1;
-
- /* query 19 */
- if (f54->query_16.has_ctrl95_query19)
- offset += 1;
-
- /* query 20 */
- if (f54->query_15.has_query20)
- offset += 1;
-
- /* query 21 */
- if (f54->query_15.has_query21) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_21.data,
- sizeof(f54->query_21.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 22 */
- if (f54->query_15.has_query22) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_22.data,
- sizeof(f54->query_22.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 23 */
- if (f54->query_22.has_query23) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_23.data,
- sizeof(f54->query_23.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 24 */
- if (f54->query_21.has_query24_data18)
- offset += 1;
-
- /* query 25 */
- if (f54->query_15.has_query25) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_25.data,
- sizeof(f54->query_25.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 26 */
- if (f54->query_22.has_ctrl103_query26)
- offset += 1;
-
- /* query 27 */
- if (f54->query_25.has_query27) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_27.data,
- sizeof(f54->query_27.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 28 */
- if (f54->query_22.has_query28)
- offset += 1;
-
- /* query 29 */
- if (f54->query_27.has_query29) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_29.data,
- sizeof(f54->query_29.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 30 */
- if (f54->query_29.has_query30) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_30.data,
- sizeof(f54->query_30.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 31 */
- if (f54->query_30.has_ctrl122_query31)
- offset += 1;
-
- /* query 32 */
- if (f54->query_30.has_query32) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_32.data,
- sizeof(f54->query_32.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 33 */
- if (f54->query_32.has_query33) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_33.data,
- sizeof(f54->query_33.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 34 */
- if (f54->query_32.has_query34)
- offset += 1;
-
- /* query 35 */
- if (f54->query_32.has_query35) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_35.data,
- sizeof(f54->query_35.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 36 */
- if (f54->query_33.has_query36) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_36.data,
- sizeof(f54->query_36.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 37 */
- if (f54->query_36.has_query37)
- offset += 1;
-
- /* query 38 */
- if (f54->query_36.has_query38) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_38.data,
- sizeof(f54->query_38.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 39 */
- if (f54->query_38.has_query39) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_39.data,
- sizeof(f54->query_39.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 40 */
- if (f54->query_39.has_query40) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_40.data,
- sizeof(f54->query_40.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 41 */
- if (f54->query_40.has_ctrl163_query41)
- offset += 1;
-
- /* query 42 */
- if (f54->query_40.has_ctrl165_query42)
- offset += 1;
-
- /* query 43 */
- if (f54->query_40.has_query43) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_43.data,
- sizeof(f54->query_43.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* queries 44 45 reserved */
-
- /* query 46 */
- if (f54->query_43.has_query46) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_46.data,
- sizeof(f54->query_46.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 47 */
- if (f54->query_46.has_query47) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_47.data,
- sizeof(f54->query_47.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 48 reserved */
-
- /* query 49 */
- if (f54->query_47.has_query49) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_49.data,
- sizeof(f54->query_49.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 50 */
- if (f54->query_49.has_query50) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_50.data,
- sizeof(f54->query_50.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 51 */
- if (f54->query_50.has_query51) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f54->query_base_addr + offset,
- f54->query_51.data,
- sizeof(f54->query_51.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- return 0;
-}
-
-static void test_f54_set_regs(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn_desc *fd,
- unsigned int intr_count,
- unsigned char page)
-{
- unsigned char ii;
- unsigned char intr_offset;
-
- f54->query_base_addr = fd->query_base_addr | (page << 8);
- f54->control_base_addr = fd->ctrl_base_addr | (page << 8);
- f54->data_base_addr = fd->data_base_addr | (page << 8);
- f54->command_base_addr = fd->cmd_base_addr | (page << 8);
-
- f54->intr_reg_num = (intr_count + 7) / 8;
- if (f54->intr_reg_num != 0)
- f54->intr_reg_num -= 1;
-
- f54->intr_mask = 0;
- intr_offset = intr_count % 8;
- for (ii = intr_offset;
- ii < (fd->intr_src_count + intr_offset);
- ii++) {
- f54->intr_mask |= 1 << ii;
- }
-
- return;
-}
-
-static int test_f55_set_queries(void)
-{
- int retval;
- unsigned char offset;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f55->query_base_addr,
- f55->query.data,
- sizeof(f55->query.data));
- if (retval < 0)
- return retval;
-
- offset = sizeof(f55->query.data);
-
- /* query 3 */
- if (f55->query.has_single_layer_multi_touch) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f55->query_base_addr + offset,
- f55->query_3.data,
- sizeof(f55->query_3.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 4 */
- if ((f55->query.has_single_layer_multi_touch) &&
- (f55->query_3.has_ctrl9))
- offset += 1;
-
- /* query 5 */
- if (f55->query.has_query5) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f55->query_base_addr + offset,
- f55->query_5.data,
- sizeof(f55->query_5.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* queries 6 7 */
- if (f55->query.curve_compensation_mode == 0x3)
- offset += 2;
-
- /* query 8 */
- if ((f55->query.has_single_layer_multi_touch) &&
- f55->query_3.has_ctrl8)
- offset += 1;
-
- /* query 9 */
- if ((f55->query.has_single_layer_multi_touch) &&
- f55->query_3.has_query9)
- offset += 1;
-
- /* queries 10 11 12 13 14 15 16 */
- if ((f55->query.has_query5) && (f55->query_5.has_basis_function))
- offset += 7;
-
- /* query 17 */
- if ((f55->query.has_query5) && (f55->query_5.has_query17)) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f55->query_base_addr + offset,
- f55->query_17.data,
- sizeof(f55->query_17.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 18 */
- if ((f55->query.has_query5) &&
- (f55->query_5.has_query17) &&
- (f55->query_17.has_query18)) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f55->query_base_addr + offset,
- f55->query_18.data,
- sizeof(f55->query_18.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 22 */
- if ((f55->query.has_query5) &&
- (f55->query_5.has_query17) &&
- (f55->query_17.has_query18) &&
- (f55->query_18.has_query22)) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f55->query_base_addr + offset,
- f55->query_22.data,
- sizeof(f55->query_22.data));
- if (retval < 0)
- return retval;
- offset += 1;
- }
-
- /* query 23 */
- if ((f55->query.has_query5) &&
- (f55->query_5.has_query17) &&
- (f55->query_17.has_query18) &&
- (f55->query_18.has_query22) &&
- (f55->query_22.has_query23)) {
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f55->query_base_addr + offset,
- f55->query_23.data,
- sizeof(f55->query_23.data));
- if (retval < 0)
- return retval;
- offset += 1;
-
- f55->amp_sensor = f55->query_23.amp_sensor_enabled;
- f55->size_of_column2mux = f55->query_23.size_of_column2mux;
- }
-
- return 0;
-}
-
-static void test_f55_init(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- unsigned char ii;
- unsigned char rx_electrodes = f54->query.num_of_rx_electrodes;
- unsigned char tx_electrodes = f54->query.num_of_tx_electrodes;
-
- retval = test_f55_set_queries();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read f55 query registers\n",
- __func__);
- return;
- }
-
- if (!f55->query.has_sensor_assignment)
- return;
-
- f55->tx_assignment = kzalloc(tx_electrodes, GFP_KERNEL);
- f55->rx_assignment = kzalloc(rx_electrodes, GFP_KERNEL);
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f55->control_base_addr + SENSOR_TX_MAPPING_OFFSET,
- f55->tx_assignment,
- tx_electrodes);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read f55 tx assignment\n",
- __func__);
- return;
- }
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- f55->control_base_addr + SENSOR_RX_MAPPING_OFFSET,
- f55->rx_assignment,
- rx_electrodes);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read f55 rx assignment\n",
- __func__);
- return;
- }
-
- f54->tx_assigned = 0;
- for (ii = 0; ii < tx_electrodes; ii++) {
- if (f55->tx_assignment[ii] != 0xff)
- f54->tx_assigned++;
- }
-
- f54->rx_assigned = 0;
- for (ii = 0; ii < rx_electrodes; ii++) {
- if (f55->rx_assignment[ii] != 0xff)
- f54->rx_assigned++;
- }
-
- if (f55->amp_sensor) {
- f54->tx_assigned = f55->size_of_column2mux;
- f54->rx_assigned /= 2;
- }
-
- return;
-}
-
-static void test_f55_set_regs(struct synaptics_rmi4_data *rmi4_data,
- struct synaptics_rmi4_fn_desc *fd,
- unsigned char page)
-{
- f55 = kzalloc(sizeof(*f55), GFP_KERNEL);
- if (!f55) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for f55\n",
- __func__);
- return;
- }
-
- f55->query_base_addr = fd->query_base_addr | (page << 8);
- f55->control_base_addr = fd->ctrl_base_addr | (page << 8);
- f55->data_base_addr = fd->data_base_addr | (page << 8);
- f55->command_base_addr = fd->cmd_base_addr | (page << 8);
-
- return;
-}
-
-static int test_scan_pdt(void)
-{
- int retval;
- unsigned char intr_count = 0;
- unsigned char page;
- unsigned short addr;
- bool f54found = false;
- bool f55found = false;
- struct synaptics_rmi4_fn_desc rmi_fd;
- struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data;
-
- for (page = 0; page < PAGES_TO_SERVICE; page++) {
- for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
- addr |= (page << 8);
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- addr,
- (unsigned char *)&rmi_fd,
- sizeof(rmi_fd));
- if (retval < 0)
- return retval;
-
- addr &= ~(MASK_8BIT << 8);
-
- if (!rmi_fd.fn_number)
- break;
-
- switch (rmi_fd.fn_number) {
- case SYNAPTICS_RMI4_F54:
- test_f54_set_regs(rmi4_data,
- &rmi_fd, intr_count, page);
- f54found = true;
- break;
- case SYNAPTICS_RMI4_F55:
- test_f55_set_regs(rmi4_data,
- &rmi_fd, page);
- f55found = true;
- break;
- default:
- break;
- }
-
- if (f54found && f55found)
- goto pdt_done;
-
- intr_count += rmi_fd.intr_src_count;
- }
- }
-
- if (!f54found) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to find F54\n",
- __func__);
- return -EINVAL;
- }
-
-pdt_done:
- return 0;
-}
-
-static void synaptics_rmi4_test_attn(struct synaptics_rmi4_data *rmi4_data,
- unsigned char intr_mask)
-{
- if (!f54)
- return;
-
- if (f54->intr_mask & intr_mask)
- queue_work(f54->test_report_workqueue, &f54->test_report_work);
-
- return;
-}
-
-static int synaptics_rmi4_test_init(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
-
- if (f54) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Handle already exists\n",
- __func__);
- return 0;
- }
-
- f54 = kzalloc(sizeof(*f54), GFP_KERNEL);
- if (!f54) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for f54\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- f54->rmi4_data = rmi4_data;
-
- f55 = NULL;
-
- retval = test_scan_pdt();
- if (retval < 0)
- goto exit_free_mem;
-
- retval = test_set_queries();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read f54 query registers\n",
- __func__);
- goto exit_free_mem;
- }
-
- f54->tx_assigned = f54->query.num_of_tx_electrodes;
- f54->rx_assigned = f54->query.num_of_rx_electrodes;
-
- retval = test_set_controls();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set up f54 control registers\n",
- __func__);
- goto exit_free_control;
- }
-
- test_set_data();
-
- if (f55)
- test_f55_init(rmi4_data);
-
- if (rmi4_data->external_afe_buttons)
- f54->tx_assigned++;
-
- retval = test_set_sysfs();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs entries\n",
- __func__);
- goto exit_sysfs;
- }
-
- f54->test_report_workqueue =
- create_singlethread_workqueue("test_report_workqueue");
- INIT_WORK(&f54->test_report_work, test_report_work);
-
- hrtimer_init(&f54->watchdog, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- f54->watchdog.function = test_get_report_timeout;
- INIT_WORK(&f54->timeout_work, test_timeout_work);
-
- mutex_init(&f54->status_mutex);
- f54->status = STATUS_IDLE;
-
- return 0;
-
-exit_sysfs:
- if (f55) {
- kfree(f55->tx_assignment);
- kfree(f55->rx_assignment);
- }
-
-exit_free_control:
- test_free_control_mem();
-
-exit_free_mem:
- kfree(f55);
- f55 = NULL;
- kfree(f54);
- f54 = NULL;
-
-exit:
- return retval;
-}
-
-static void synaptics_rmi4_test_remove(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!f54)
- goto exit;
-
- hrtimer_cancel(&f54->watchdog);
-
- cancel_work_sync(&f54->test_report_work);
- flush_workqueue(f54->test_report_workqueue);
- destroy_workqueue(f54->test_report_workqueue);
-
- test_remove_sysfs();
-
- if (f55) {
- kfree(f55->tx_assignment);
- kfree(f55->rx_assignment);
- }
-
- test_free_control_mem();
-
- if (f54->data_buffer_size)
- kfree(f54->report_data);
-
- kfree(f55);
- f55 = NULL;
-
- kfree(f54);
- f54 = NULL;
-
-exit:
- complete(&test_remove_complete);
-
- return;
-}
-
-static void synaptics_rmi4_test_reset(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
-
- if (!f54) {
- synaptics_rmi4_test_init(rmi4_data);
- return;
- }
-
- if (f55) {
- kfree(f55->tx_assignment);
- kfree(f55->rx_assignment);
- }
-
- test_free_control_mem();
-
- kfree(f55);
- f55 = NULL;
-
- retval = test_scan_pdt();
- if (retval < 0)
- goto exit_free_mem;
-
- retval = test_set_queries();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to read f54 query registers\n",
- __func__);
- goto exit_free_mem;
- }
-
- f54->tx_assigned = f54->query.num_of_tx_electrodes;
- f54->rx_assigned = f54->query.num_of_rx_electrodes;
-
- retval = test_set_controls();
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to set up f54 control registers\n",
- __func__);
- goto exit_free_control;
- }
-
- test_set_data();
-
- if (f55)
- test_f55_init(rmi4_data);
-
- if (rmi4_data->external_afe_buttons)
- f54->tx_assigned++;
-
- f54->status = STATUS_IDLE;
-
- return;
-
-exit_free_control:
- test_free_control_mem();
-
-exit_free_mem:
- hrtimer_cancel(&f54->watchdog);
-
- cancel_work_sync(&f54->test_report_work);
- flush_workqueue(f54->test_report_workqueue);
- destroy_workqueue(f54->test_report_workqueue);
-
- test_remove_sysfs();
-
- if (f54->data_buffer_size)
- kfree(f54->report_data);
-
- kfree(f55);
- f55 = NULL;
-
- kfree(f54);
- f54 = NULL;
-
- return;
-}
-
-static struct synaptics_rmi4_exp_fn test_module = {
- .fn_type = RMI_TEST_REPORTING,
- .init = synaptics_rmi4_test_init,
- .remove = synaptics_rmi4_test_remove,
- .reset = synaptics_rmi4_test_reset,
- .reinit = NULL,
- .early_suspend = NULL,
- .suspend = NULL,
- .resume = NULL,
- .late_resume = NULL,
- .attn = synaptics_rmi4_test_attn,
-};
-
-static int __init rmi4_test_module_init(void)
-{
- synaptics_rmi4_new_function(&test_module, true);
-
- return 0;
-}
-
-static void __exit rmi4_test_module_exit(void)
-{
- synaptics_rmi4_new_function(&test_module, false);
-
- wait_for_completion(&test_remove_complete);
-
- return;
-}
-
-module_init(rmi4_test_module_init);
-module_exit(rmi4_test_module_exit);
-
-MODULE_AUTHOR("Synaptics, Inc.");
-MODULE_DESCRIPTION("Synaptics DSX Test Reporting Module");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c
deleted file mode 100644
index 847dc4dd3049..000000000000
--- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_video.c
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/platform_device.h>
-#include <linux/input/synaptics_dsx_v2_6.h>
-#include "synaptics_dsx_core.h"
-
-#define SYSFS_FOLDER_NAME "video"
-
-/*
-#define RMI_DCS_SUSPEND_RESUME
-*/
-
-static ssize_t video_sysfs_dcs_write_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static ssize_t video_sysfs_param_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count);
-
-static int video_send_dcs_command(unsigned char command_opcode);
-
-struct f38_command {
- union {
- struct {
- unsigned char command_opcode;
- unsigned char register_access:1;
- unsigned char gamma_page:1;
- unsigned char f38_control1_b2__7:6;
- unsigned char parameter_field_1;
- unsigned char parameter_field_2;
- unsigned char parameter_field_3;
- unsigned char parameter_field_4;
- unsigned char send_to_dcs:1;
- unsigned char f38_command6_b1__7:7;
- } __packed;
- unsigned char data[7];
- };
-};
-
-struct synaptics_rmi4_video_handle {
- unsigned char param;
- unsigned short query_base_addr;
- unsigned short control_base_addr;
- unsigned short data_base_addr;
- unsigned short command_base_addr;
- struct synaptics_rmi4_data *rmi4_data;
- struct kobject *sysfs_dir;
-};
-
-#ifdef RMI_DCS_SUSPEND_RESUME
-struct dcs_command {
- unsigned char command;
- unsigned int wait_time;
-};
-
-static struct dcs_command suspend_sequence[] = {
- {
- .command = 0x28,
- .wait_time = 200,
- },
- {
- .command = 0x10,
- .wait_time = 200,
- },
-};
-
-static struct dcs_command resume_sequence[] = {
- {
- .command = 0x11,
- .wait_time = 200,
- },
- {
- .command = 0x29,
- .wait_time = 200,
- },
-};
-#endif
-
-static struct device_attribute attrs[] = {
- __ATTR(dcs_write, S_IWUGO,
- NULL,
- video_sysfs_dcs_write_store),
- __ATTR(param, S_IWUGO,
- NULL,
- video_sysfs_param_store),
-};
-
-static struct synaptics_rmi4_video_handle *video;
-
-DECLARE_COMPLETION(video_remove_complete);
-
-static ssize_t video_sysfs_dcs_write_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int retval;
- unsigned int input;
-
- if (sscanf(buf, "%x", &input) != 1)
- return -EINVAL;
-
- retval = video_send_dcs_command((unsigned char)input);
- if (retval < 0)
- return retval;
-
- return count;
-}
-
-static ssize_t video_sysfs_param_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- unsigned int input;
-
- if (sscanf(buf, "%x", &input) != 1)
- return -EINVAL;
-
- video->param = (unsigned char)input;
-
- return count;
-}
-
-static int video_send_dcs_command(unsigned char command_opcode)
-{
- int retval;
- struct f38_command command;
- struct synaptics_rmi4_data *rmi4_data = video->rmi4_data;
-
- memset(&command, 0x00, sizeof(command));
-
- command.command_opcode = command_opcode;
- command.parameter_field_1 = video->param;
- command.send_to_dcs = 1;
-
- video->param = 0;
-
- retval = synaptics_rmi4_reg_write(rmi4_data,
- video->command_base_addr,
- command.data,
- sizeof(command.data));
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to send DCS command\n",
- __func__);
- return retval;
- }
-
- return 0;
-}
-
-static int video_scan_pdt(void)
-{
- int retval;
- unsigned char page;
- unsigned short addr;
- bool f38_found = false;
- struct synaptics_rmi4_fn_desc rmi_fd;
- struct synaptics_rmi4_data *rmi4_data = video->rmi4_data;
-
- for (page = 0; page < PAGES_TO_SERVICE; page++) {
- for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
- addr |= (page << 8);
-
- retval = synaptics_rmi4_reg_read(rmi4_data,
- addr,
- (unsigned char *)&rmi_fd,
- sizeof(rmi_fd));
- if (retval < 0)
- return retval;
-
- addr &= ~(MASK_8BIT << 8);
-
- if (!rmi_fd.fn_number)
- break;
-
- if (rmi_fd.fn_number == SYNAPTICS_RMI4_F38) {
- f38_found = true;
- goto f38_found;
- }
- }
- }
-
- if (!f38_found) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to find F38\n",
- __func__);
- return -EINVAL;
- }
-
-f38_found:
- video->query_base_addr = rmi_fd.query_base_addr | (page << 8);
- video->control_base_addr = rmi_fd.ctrl_base_addr | (page << 8);
- video->data_base_addr = rmi_fd.data_base_addr | (page << 8);
- video->command_base_addr = rmi_fd.cmd_base_addr | (page << 8);
-
- return 0;
-}
-
-static int synaptics_rmi4_video_init(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- unsigned char attr_count;
-
- if (video) {
- dev_dbg(rmi4_data->pdev->dev.parent,
- "%s: Handle already exists\n",
- __func__);
- return 0;
- }
-
- video = kzalloc(sizeof(*video), GFP_KERNEL);
- if (!video) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to alloc mem for video\n",
- __func__);
- retval = -ENOMEM;
- goto exit;
- }
-
- video->rmi4_data = rmi4_data;
-
- retval = video_scan_pdt();
- if (retval < 0) {
- retval = 0;
- goto exit_scan_pdt;
- }
-
- video->sysfs_dir = kobject_create_and_add(SYSFS_FOLDER_NAME,
- &rmi4_data->input_dev->dev.kobj);
- if (!video->sysfs_dir) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs directory\n",
- __func__);
- retval = -ENODEV;
- goto exit_sysfs_dir;
- }
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
- retval = sysfs_create_file(video->sysfs_dir,
- &attrs[attr_count].attr);
- if (retval < 0) {
- dev_err(rmi4_data->pdev->dev.parent,
- "%s: Failed to create sysfs attributes\n",
- __func__);
- retval = -ENODEV;
- goto exit_sysfs_attrs;
- }
- }
-
- return 0;
-
-exit_sysfs_attrs:
- for (attr_count--; attr_count >= 0; attr_count--)
- sysfs_remove_file(video->sysfs_dir, &attrs[attr_count].attr);
-
- kobject_put(video->sysfs_dir);
-
-exit_sysfs_dir:
-exit_scan_pdt:
- kfree(video);
- video = NULL;
-
-exit:
- return retval;
-}
-
-static void synaptics_rmi4_video_remove(struct synaptics_rmi4_data *rmi4_data)
-{
- unsigned char attr_count;
-
- if (!video)
- goto exit;
-
- for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++)
- sysfs_remove_file(video->sysfs_dir, &attrs[attr_count].attr);
-
- kobject_put(video->sysfs_dir);
-
- kfree(video);
- video = NULL;
-
-exit:
- complete(&video_remove_complete);
-
- return;
-}
-
-static void synaptics_rmi4_video_reset(struct synaptics_rmi4_data *rmi4_data)
-{
- if (!video)
- synaptics_rmi4_video_init(rmi4_data);
-
- return;
-}
-
-#ifdef RMI_DCS_SUSPEND_RESUME
-static void synaptics_rmi4_video_suspend(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- unsigned char ii;
- unsigned char command;
- unsigned char num_of_cmds;
-
- if (!video)
- return;
-
- num_of_cmds = ARRAY_SIZE(suspend_sequence);
-
- for (ii = 0; ii < num_of_cmds; ii++) {
- command = suspend_sequence[ii].command;
- retval = video_send_dcs_command(command);
- if (retval < 0)
- return;
- msleep(suspend_sequence[ii].wait_time);
- }
-
- return;
-}
-
-static void synaptics_rmi4_video_resume(struct synaptics_rmi4_data *rmi4_data)
-{
- int retval;
- unsigned char ii;
- unsigned char command;
- unsigned char num_of_cmds;
-
- if (!video)
- return;
-
- num_of_cmds = ARRAY_SIZE(resume_sequence);
-
- for (ii = 0; ii < num_of_cmds; ii++) {
- command = resume_sequence[ii].command;
- retval = video_send_dcs_command(command);
- if (retval < 0)
- return;
- msleep(resume_sequence[ii].wait_time);
- }
-
- return;
-}
-#endif
-
-static struct synaptics_rmi4_exp_fn video_module = {
- .fn_type = RMI_VIDEO,
- .init = synaptics_rmi4_video_init,
- .remove = synaptics_rmi4_video_remove,
- .reset = synaptics_rmi4_video_reset,
- .reinit = NULL,
- .early_suspend = NULL,
-#ifdef RMI_DCS_SUSPEND_RESUME
- .suspend = synaptics_rmi4_video_suspend,
- .resume = synaptics_rmi4_video_resume,
-#else
- .suspend = NULL,
- .resume = NULL,
-#endif
- .late_resume = NULL,
- .attn = NULL,
-};
-
-static int __init rmi4_video_module_init(void)
-{
- synaptics_rmi4_new_function(&video_module, true);
-
- return 0;
-}
-
-static void __exit rmi4_video_module_exit(void)
-{
- synaptics_rmi4_new_function(&video_module, false);
-
- wait_for_completion(&video_remove_complete);
-
- return;
-}
-
-module_init(rmi4_video_module_init);
-module_exit(rmi4_video_module_exit);
-
-MODULE_AUTHOR("Synaptics, Inc.");
-MODULE_DESCRIPTION("Synaptics DSX Video Module");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 9413b0726237..f0fc6f7b5d98 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3238,13 +3238,14 @@ static int __init init_dmars(void)
iommu_identity_mapping |= IDENTMAP_GFX;
#endif
+ check_tylersburg_isoch();
+
if (iommu_identity_mapping) {
ret = si_domain_init(hw_pass_through);
if (ret)
goto free_iommu;
}
- check_tylersburg_isoch();
/*
* If we copied translations from a previous kernel in the kdump
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 6b420a55c745..c3ea03c9a1a8 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -425,7 +425,7 @@ struct cache {
* until a gc finishes - otherwise we could pointlessly burn a ton of
* cpu
*/
- unsigned invalidate_needs_gc:1;
+ unsigned invalidate_needs_gc;
bool discard; /* Get rid of? */
@@ -593,8 +593,8 @@ struct cache_set {
/* Counts how many sectors bio_insert has added to the cache */
atomic_t sectors_to_gc;
+ wait_queue_head_t gc_wait;
- wait_queue_head_t moving_gc_wait;
struct keybuf moving_gc_keys;
/* Number of moving GC bios in flight */
struct semaphore moving_in_flight;
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 22b9e34ceb75..5b815e64c1c9 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -1762,33 +1762,34 @@ static void bch_btree_gc(struct cache_set *c)
bch_moving_gc(c);
}
-static int bch_gc_thread(void *arg)
+static bool gc_should_run(struct cache_set *c)
{
- struct cache_set *c = arg;
struct cache *ca;
unsigned i;
- while (1) {
-again:
- bch_btree_gc(c);
+ for_each_cache(ca, c, i)
+ if (ca->invalidate_needs_gc)
+ return true;
- set_current_state(TASK_INTERRUPTIBLE);
- if (kthread_should_stop())
- break;
+ if (atomic_read(&c->sectors_to_gc) < 0)
+ return true;
- mutex_lock(&c->bucket_lock);
+ return false;
+}
- for_each_cache(ca, c, i)
- if (ca->invalidate_needs_gc) {
- mutex_unlock(&c->bucket_lock);
- set_current_state(TASK_RUNNING);
- goto again;
- }
+static int bch_gc_thread(void *arg)
+{
+ struct cache_set *c = arg;
- mutex_unlock(&c->bucket_lock);
+ while (1) {
+ wait_event_interruptible(c->gc_wait,
+ kthread_should_stop() || gc_should_run(c));
- try_to_freeze();
- schedule();
+ if (kthread_should_stop())
+ break;
+
+ set_gc_sectors(c);
+ bch_btree_gc(c);
}
return 0;
@@ -1796,11 +1797,10 @@ again:
int bch_gc_thread_start(struct cache_set *c)
{
- c->gc_thread = kthread_create(bch_gc_thread, c, "bcache_gc");
+ c->gc_thread = kthread_run(bch_gc_thread, c, "bcache_gc");
if (IS_ERR(c->gc_thread))
return PTR_ERR(c->gc_thread);
- set_task_state(c->gc_thread, TASK_INTERRUPTIBLE);
return 0;
}
diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h
index 5c391fa01bed..9b80417cd547 100644
--- a/drivers/md/bcache/btree.h
+++ b/drivers/md/bcache/btree.h
@@ -260,8 +260,7 @@ void bch_initial_mark_key(struct cache_set *, int, struct bkey *);
static inline void wake_up_gc(struct cache_set *c)
{
- if (c->gc_thread)
- wake_up_process(c->gc_thread);
+ wake_up(&c->gc_wait);
}
#define MAP_DONE 0
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 25fa8445bb24..2410df1c2a05 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -196,10 +196,8 @@ static void bch_data_insert_start(struct closure *cl)
struct data_insert_op *op = container_of(cl, struct data_insert_op, cl);
struct bio *bio = op->bio, *n;
- if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0) {
- set_gc_sectors(op->c);
+ if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0)
wake_up_gc(op->c);
- }
if (op->bypass)
return bch_data_invalidate(cl);
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 3d5c0ba13181..7b5880b8874c 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1489,6 +1489,7 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
mutex_init(&c->bucket_lock);
init_waitqueue_head(&c->btree_cache_wait);
init_waitqueue_head(&c->bucket_wait);
+ init_waitqueue_head(&c->gc_wait);
sema_init(&c->uuid_write_mutex, 1);
spin_lock_init(&c->btree_gc_time.lock);
@@ -1547,6 +1548,7 @@ static void run_cache_set(struct cache_set *c)
for_each_cache(ca, c, i)
c->nbuckets += ca->sb.nbuckets;
+ set_gc_sectors(c);
if (CACHE_SYNC(&c->sb)) {
LIST_HEAD(journal);
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index bb9b92ebbf8e..0da5efaad85c 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -248,7 +248,7 @@ struct cache {
/*
* Fields for converting from sectors to blocks.
*/
- uint32_t sectors_per_block;
+ sector_t sectors_per_block;
int sectors_per_block_shift;
spinlock_t lock;
@@ -3544,11 +3544,11 @@ static void cache_status(struct dm_target *ti, status_type_t type,
residency = policy_residency(cache->policy);
- DMEMIT("%u %llu/%llu %u %llu/%llu %u %u %u %u %u %u %lu ",
+ DMEMIT("%u %llu/%llu %llu %llu/%llu %u %u %u %u %u %u %lu ",
(unsigned)DM_CACHE_METADATA_BLOCK_SIZE,
(unsigned long long)(nr_blocks_metadata - nr_free_blocks_metadata),
(unsigned long long)nr_blocks_metadata,
- cache->sectors_per_block,
+ (unsigned long long)cache->sectors_per_block,
(unsigned long long) from_cblock(residency),
(unsigned long long) from_cblock(cache->cache_size),
(unsigned) atomic_read(&cache->stats.read_hit),
diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c
index 8289804ccd99..d5ea9f28ae70 100644
--- a/drivers/md/dm-stats.c
+++ b/drivers/md/dm-stats.c
@@ -175,6 +175,7 @@ static void dm_stat_free(struct rcu_head *head)
int cpu;
struct dm_stat *s = container_of(head, struct dm_stat, rcu_head);
+ kfree(s->histogram_boundaries);
kfree(s->program_id);
kfree(s->aux_data);
for_each_possible_cpu(cpu) {
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index dd1cde5458b8..e9b34de2319e 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1467,11 +1467,62 @@ void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors)
}
EXPORT_SYMBOL_GPL(dm_accept_partial_bio);
+/*
+ * Flush current->bio_list when the target map method blocks.
+ * This fixes deadlocks in snapshot and possibly in other targets.
+ */
+struct dm_offload {
+ struct blk_plug plug;
+ struct blk_plug_cb cb;
+};
+
+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;
+
+ 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;
+ }
+
+ 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);
+ }
+}
+
+static void dm_offload_start(struct dm_offload *o)
+{
+ blk_start_plug(&o->plug);
+ o->cb.callback = flush_current_bio_list;
+ list_add(&o->cb.list, &current->plug->cb_list);
+}
+
+static void dm_offload_end(struct dm_offload *o)
+{
+ list_del(&o->cb.list);
+ blk_finish_plug(&o->plug);
+}
+
static void __map_bio(struct dm_target_io *tio)
{
int r;
sector_t sector;
struct mapped_device *md;
+ struct dm_offload o;
struct bio *clone = &tio->clone;
struct dm_target *ti = tio->ti;
@@ -1484,7 +1535,11 @@ static void __map_bio(struct dm_target_io *tio)
*/
atomic_inc(&tio->io->io_count);
sector = clone->bi_iter.bi_sector;
+
+ dm_offload_start(&o);
r = ti->type->map(ti, clone);
+ dm_offload_end(&o);
+
if (r == DM_MAPIO_REMAPPED) {
/* the bio has been remapped so dispatch it */
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index b7fe7e9fc777..6ba3227e29b2 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -52,18 +52,26 @@ static inline struct dev_info *which_dev(struct mddev *mddev, sector_t sector)
return conf->disks + lo;
}
+/*
+ * In linear_congested() conf->raid_disks is used as a copy of
+ * mddev->raid_disks to iterate conf->disks[], because conf->raid_disks
+ * and conf->disks[] are created in linear_conf(), they are always
+ * consitent with each other, but mddev->raid_disks does not.
+ */
static int linear_congested(struct mddev *mddev, int bits)
{
struct linear_conf *conf;
int i, ret = 0;
- conf = mddev->private;
+ rcu_read_lock();
+ conf = rcu_dereference(mddev->private);
- for (i = 0; i < mddev->raid_disks && !ret ; i++) {
+ for (i = 0; i < conf->raid_disks && !ret ; i++) {
struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev);
ret |= bdi_congested(&q->backing_dev_info, bits);
}
+ rcu_read_unlock();
return ret;
}
@@ -143,6 +151,19 @@ static struct linear_conf *linear_conf(struct mddev *mddev, int raid_disks)
conf->disks[i-1].end_sector +
conf->disks[i].rdev->sectors;
+ /*
+ * conf->raid_disks is copy of mddev->raid_disks. The reason to
+ * keep a copy of mddev->raid_disks in struct linear_conf is,
+ * mddev->raid_disks may not be consistent with pointers number of
+ * conf->disks[] when it is updated in linear_add() and used to
+ * iterate old conf->disks[] earray in linear_congested().
+ * Here conf->raid_disks is always consitent with number of
+ * pointers in conf->disks[] array, and mddev->private is updated
+ * with rcu_assign_pointer() in linear_addr(), such race can be
+ * avoided.
+ */
+ conf->raid_disks = raid_disks;
+
return conf;
out:
@@ -195,15 +216,23 @@ static int linear_add(struct mddev *mddev, struct md_rdev *rdev)
if (!newconf)
return -ENOMEM;
+ /* newconf->raid_disks already keeps a copy of * the increased
+ * value of mddev->raid_disks, WARN_ONCE() is just used to make
+ * sure of this. It is possible that oldconf is still referenced
+ * in linear_congested(), therefore kfree_rcu() is used to free
+ * oldconf until no one uses it anymore.
+ */
mddev_suspend(mddev);
- oldconf = mddev->private;
+ oldconf = rcu_dereference(mddev->private);
mddev->raid_disks++;
- mddev->private = newconf;
+ WARN_ONCE(mddev->raid_disks != newconf->raid_disks,
+ "copied raid_disks doesn't match mddev->raid_disks");
+ rcu_assign_pointer(mddev->private, newconf);
md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
set_capacity(mddev->gendisk, mddev->array_sectors);
mddev_resume(mddev);
revalidate_disk(mddev->gendisk);
- kfree(oldconf);
+ kfree_rcu(oldconf, rcu);
return 0;
}
diff --git a/drivers/md/linear.h b/drivers/md/linear.h
index b685ddd7d7f7..8d392e6098b3 100644
--- a/drivers/md/linear.h
+++ b/drivers/md/linear.h
@@ -10,6 +10,7 @@ struct linear_conf
{
struct rcu_head rcu;
sector_t array_sectors;
+ int raid_disks; /* a copy of mddev->raid_disks */
struct dev_info disks[0];
};
#endif
diff --git a/drivers/media/pci/dm1105/Kconfig b/drivers/media/pci/dm1105/Kconfig
index 173daf0c0847..14fa7e40f2a6 100644
--- a/drivers/media/pci/dm1105/Kconfig
+++ b/drivers/media/pci/dm1105/Kconfig
@@ -1,6 +1,6 @@
config DVB_DM1105
tristate "SDMC DM1105 based PCI cards"
- depends on DVB_CORE && PCI && I2C
+ depends on DVB_CORE && PCI && I2C && I2C_ALGOBIT
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c
index ba780c45f645..572bc043b62d 100644
--- a/drivers/media/platform/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/am437x/am437x-vpfe.c
@@ -1576,7 +1576,7 @@ static int vpfe_s_fmt(struct file *file, void *priv,
return -EBUSY;
}
- ret = vpfe_try_fmt(file, priv, &format);
+ ret = __vpfe_get_format(vpfe, &format, &bpp);
if (ret)
return ret;
diff --git a/drivers/media/platform/msm/camera_v2/camera/camera.c b/drivers/media/platform/msm/camera_v2/camera/camera.c
index 3985df780216..df0664b496ba 100644
--- a/drivers/media/platform/msm/camera_v2/camera/camera.c
+++ b/drivers/media/platform/msm/camera_v2/camera/camera.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -486,6 +486,9 @@ static long camera_v4l2_vidioc_private_ioctl(struct file *filep, void *fh,
if (WARN_ON(!k_ioctl || !pvdev))
return -EIO;
+ if (cmd != VIDIOC_MSM_CAMERA_PRIVATE_IOCTL_CMD)
+ return -EINVAL;
+
switch (k_ioctl->id) {
case MSM_CAMERA_PRIV_IOCTL_ID_RETURN_BUF: {
struct msm_camera_return_buf ptr, *tmp = NULL;
diff --git a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c
index 34fffa8dd7ce..a0c606ce9a29 100644
--- a/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c
+++ b/drivers/media/platform/msm/camera_v2/common/cam_soc_api.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -376,18 +376,17 @@ int msm_camera_clk_enable(struct device *dev,
if (clk_rate == 0) {
clk_rate =
clk_round_rate(clk_ptr[i], 0);
- if (clk_rate < 0) {
+ if (clk_rate <= 0) {
pr_err("%s round rate failed\n",
clk_info[i].clk_name);
goto cam_clk_set_err;
}
- rc = clk_set_rate(clk_ptr[i],
- clk_rate);
- if (rc < 0) {
- pr_err("%s set rate failed\n",
- clk_info[i].clk_name);
- goto cam_clk_set_err;
- }
+ }
+ rc = clk_set_rate(clk_ptr[i], clk_rate);
+ if (rc < 0) {
+ pr_err("%s set rate failed\n",
+ clk_info[i].clk_name);
+ goto cam_clk_set_err;
}
}
rc = clk_prepare_enable(clk_ptr[i]);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index f2f3388b41c1..737433209c2b 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -509,6 +509,14 @@ static int vfe_probe(struct platform_device *pdev)
for (i = 0; i < (MSM_ISP_STATS_MAX * MAX_VFE); i++)
spin_lock_init(&(vfe_common_data.stats_streams[i].lock));
+ for (i = 0; i <= MAX_VFE; i++) {
+ INIT_LIST_HEAD(&vfe_common_data.tasklets[i].tasklet_q);
+ tasklet_init(&vfe_common_data.tasklets[i].tasklet,
+ msm_isp_do_tasklet,
+ (unsigned long)(&vfe_common_data.tasklets[i]));
+ spin_lock_init(&vfe_common_data.tasklets[i].tasklet_lock);
+ }
+
of_property_read_u32(pdev->dev.of_node,
"num_child", &vfe_parent_dev->num_hw_sd);
@@ -615,10 +623,6 @@ int vfe_hw_probe(struct platform_device *pdev)
goto probe_fail3;
}
- INIT_LIST_HEAD(&vfe_dev->tasklet_q);
- tasklet_init(&vfe_dev->vfe_tasklet,
- msm_isp_do_tasklet, (unsigned long)vfe_dev);
-
v4l2_subdev_init(&vfe_dev->subdev.sd, &msm_vfe_v4l2_subdev_ops);
vfe_dev->subdev.sd.internal_ops =
&msm_vfe_subdev_internal_ops;
@@ -631,7 +635,6 @@ int vfe_hw_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, &vfe_dev->subdev.sd);
mutex_init(&vfe_dev->realtime_mutex);
mutex_init(&vfe_dev->core_mutex);
- spin_lock_init(&vfe_dev->tasklet_lock);
spin_lock_init(&vfe_dev->shared_data_lock);
spin_lock_init(&vfe_dev->reg_update_lock);
spin_lock_init(&req_history_lock);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 0325c5ded3cf..139a4c9b49ee 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -162,6 +162,8 @@ struct msm_vfe_irq_ops {
void (*config_irq)(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
enum msm_isp_irq_operation);
+ void (*preprocess_camif_irq)(struct vfe_device *vfe_dev,
+ uint32_t irq_status0);
};
struct msm_vfe_axi_ops {
@@ -282,7 +284,7 @@ struct msm_vfe_stats_ops {
void (*update_ping_pong_addr)(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info,
- uint32_t pingpong_status, dma_addr_t paddr);
+ uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_size);
uint32_t (*get_frame_id)(struct vfe_device *vfe_dev);
uint32_t (*get_wm_mask)(uint32_t irq_status0, uint32_t irq_status1);
@@ -494,6 +496,7 @@ struct msm_vfe_src_info {
struct timeval time_stamp;
enum msm_vfe_dual_hw_type dual_hw_type;
struct msm_vfe_dual_hw_ms_info dual_hw_ms_info;
+ bool accept_frame;
};
struct msm_vfe_fetch_engine_info {
@@ -593,6 +596,7 @@ struct msm_vfe_tasklet_queue_cmd {
uint32_t vfeInterruptStatus1;
struct msm_isp_timestamp ts;
uint8_t cmd_used;
+ struct vfe_device *vfe_dev;
};
#define MSM_VFE_TASKLETQ_SIZE 200
@@ -717,6 +721,15 @@ struct msm_vfe_irq_dump {
tasklet_debug[MAX_VFE_IRQ_DEBUG_DUMP_SIZE];
};
+struct msm_vfe_tasklet {
+ spinlock_t tasklet_lock;
+ uint8_t taskletq_idx;
+ struct list_head tasklet_q;
+ struct tasklet_struct tasklet;
+ struct msm_vfe_tasklet_queue_cmd
+ tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE];
+};
+
struct msm_vfe_common_dev_data {
spinlock_t common_dev_data_lock;
struct dual_vfe_resource *dual_vfe_res;
@@ -726,6 +739,7 @@ struct msm_vfe_common_dev_data {
struct mutex vfe_common_mutex;
/* Irq debug Info */
struct msm_vfe_irq_dump vfe_irq_dump;
+ struct msm_vfe_tasklet tasklets[MAX_VFE + 1];
};
struct msm_vfe_common_subdev {
@@ -767,6 +781,7 @@ struct vfe_device {
struct msm_cam_clk_info *hvx_clk_info;
size_t num_hvx_clk;
size_t num_norm_clk;
+ bool hvx_clk_state;
enum cam_ahb_clk_vote ahb_vote;
struct cx_ipeak_client *vfe_cx_ipeak;
@@ -777,15 +792,9 @@ struct vfe_device {
struct mutex core_mutex;
spinlock_t shared_data_lock;
spinlock_t reg_update_lock;
- spinlock_t tasklet_lock;
/* Tasklet info */
atomic_t irq_cnt;
- uint8_t taskletq_idx;
- struct list_head tasklet_q;
- struct tasklet_struct vfe_tasklet;
- struct msm_vfe_tasklet_queue_cmd
- tasklet_queue_cmd[MSM_VFE_TASKLETQ_SIZE];
/* Data structures */
struct msm_vfe_hardware_info *hw_info;
@@ -798,7 +807,6 @@ struct vfe_device {
/* State variables */
uint32_t vfe_hw_version;
- int vfe_clk_idx;
uint32_t vfe_open_cnt;
uint8_t vt_enable;
uint32_t vfe_ub_policy;
@@ -815,7 +823,6 @@ struct vfe_device {
struct msm_isp_statistics *stats;
uint64_t msm_isp_last_overflow_ab;
uint64_t msm_isp_last_overflow_ib;
- uint32_t msm_isp_vfe_clk_rate;
struct msm_isp_ub_info *ub_info;
uint32_t isp_sof_debug;
uint32_t isp_raw0_debug;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index bf18fc59585c..caf69af25601 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -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
@@ -1305,7 +1305,7 @@ static void msm_vfe32_stats_enable_module(struct vfe_device *vfe_dev,
static void msm_vfe32_stats_update_ping_pong_addr(struct vfe_device *vfe_dev,
struct msm_vfe_stats_stream *stream_info, uint32_t pingpong_status,
- dma_addr_t paddr)
+ dma_addr_t paddr, uint32_t buf_sz)
{
void __iomem *vfe_base = vfe_dev->vfe_base;
int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 8e549c338bdd..f5533fd9062e 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -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
@@ -2114,7 +2114,7 @@ static void msm_vfe40_stats_enable_module(struct vfe_device *vfe_dev,
static void msm_vfe40_stats_update_ping_pong_addr(
struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info,
- uint32_t pingpong_status, dma_addr_t paddr)
+ uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_sz)
{
void __iomem *vfe_base = vfe_dev->vfe_base;
int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
@@ -2218,6 +2218,7 @@ struct msm_vfe_hardware_info vfe40_hw_info = {
.process_stats_irq = msm_isp_process_stats_irq,
.process_epoch_irq = msm_vfe40_process_epoch_irq,
.config_irq = msm_vfe40_config_irq,
+ .preprocess_camif_irq = msm_isp47_preprocess_camif_irq,
},
.axi_ops = {
.reload_wm = msm_vfe40_axi_reload_wm,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
index 957cbc292be3..c85bf1655b8c 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c
@@ -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
@@ -1720,7 +1720,7 @@ static void msm_vfe44_stats_update_cgc_override(struct vfe_device *vfe_dev,
static void msm_vfe44_stats_update_ping_pong_addr(
struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info,
- uint32_t pingpong_status, dma_addr_t paddr)
+ uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_sz)
{
void __iomem *vfe_base = vfe_dev->vfe_base;
int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
@@ -1825,6 +1825,7 @@ struct msm_vfe_hardware_info vfe44_hw_info = {
.process_stats_irq = msm_isp_process_stats_irq,
.process_epoch_irq = msm_vfe44_process_epoch_irq,
.config_irq = msm_vfe44_config_irq,
+ .preprocess_camif_irq = msm_isp47_preprocess_camif_irq,
},
.axi_ops = {
.reload_wm = msm_vfe44_axi_reload_wm,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
index cc768db875db..72ce32940c29 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c
@@ -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
@@ -1798,7 +1798,7 @@ static void msm_vfe46_stats_enable_module(struct vfe_device *vfe_dev,
static void msm_vfe46_stats_update_ping_pong_addr(
struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info,
- uint32_t pingpong_status, dma_addr_t paddr)
+ uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_sz)
{
void __iomem *vfe_base = vfe_dev->vfe_base;
int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
@@ -1902,6 +1902,7 @@ struct msm_vfe_hardware_info vfe46_hw_info = {
.process_stats_irq = msm_isp_process_stats_irq,
.process_epoch_irq = msm_vfe46_process_epoch_irq,
.config_irq = msm_vfe46_config_irq,
+ .preprocess_camif_irq = msm_isp47_preprocess_camif_irq,
},
.axi_ops = {
.reload_wm = msm_vfe46_axi_reload_wm,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
index b351e0e765a9..a66ca7e93537 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
@@ -281,9 +281,11 @@ int msm_isp47_ahb_clk_cfg(struct vfe_device *vfe_dev,
vfe_dev->hw_info->vfe_ops.platform_ops.get_clk_rates(vfe_dev,
&clk_rates);
- if (vfe_dev->msm_isp_vfe_clk_rate <= clk_rates.svs_rate)
+ if (vfe_dev->vfe_clk_info[vfe_dev->hw_info->vfe_clk_idx].clk_rate <=
+ clk_rates.svs_rate)
src_clk_vote = CAM_AHB_SVS_VOTE;
- else if (vfe_dev->msm_isp_vfe_clk_rate <= clk_rates.nominal_rate)
+ else if (vfe_dev->vfe_clk_info[vfe_dev->hw_info->vfe_clk_idx].clk_rate
+ <= clk_rates.nominal_rate)
src_clk_vote = CAM_AHB_NOMINAL_VOTE;
else
src_clk_vote = CAM_AHB_TURBO_VOTE;
@@ -365,7 +367,8 @@ void msm_vfe47_release_hardware(struct vfe_device *vfe_dev)
vfe_dev->irq0_mask, vfe_dev->irq1_mask,
MSM_ISP_IRQ_SET);
msm_camera_enable_irq(vfe_dev->vfe_irq, 0);
- tasklet_kill(&vfe_dev->vfe_tasklet);
+ tasklet_kill(&(vfe_dev->common_data->tasklets[vfe_dev->pdev->id].
+ tasklet));
msm_isp_flush_tasklet(vfe_dev);
vfe_dev->common_data->dual_vfe_res->vfe_base[vfe_dev->pdev->id] = NULL;
@@ -386,6 +389,7 @@ void msm_vfe47_release_hardware(struct vfe_device *vfe_dev)
vfe_dev->hw_info->vfe_ops.platform_ops.enable_clks(
vfe_dev, 0);
+ msm_vfe47_configure_hvx(vfe_dev, 0);
vfe_dev->hw_info->vfe_ops.platform_ops.enable_regulators(vfe_dev, 0);
}
@@ -488,7 +492,7 @@ void msm_vfe47_process_violation_status(
return;
}
- pr_err("%s: VFE pipeline violation status %d\n", __func__,
+ pr_err_ratelimited("%s: VFE pipeline violation status %d\n", __func__,
violation_status);
}
@@ -685,6 +689,15 @@ void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev,
}
}
+void msm_isp47_preprocess_camif_irq(struct vfe_device *vfe_dev,
+ uint32_t irq_status0)
+{
+ if (irq_status0 & BIT(1))
+ vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = false;
+ if (irq_status0 & BIT(0))
+ vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = true;
+}
+
void msm_vfe47_reg_update(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src)
{
@@ -1390,7 +1403,7 @@ void msm_vfe47_cfg_camif(struct vfe_device *vfe_dev,
if (subsample_period && subsample_pattern) {
val = msm_camera_io_r(vfe_dev->vfe_base + 0x494);
val &= 0xFFFFE0FF;
- val = (subsample_period - 1) << 8;
+ val |= (subsample_period - 1) << 8;
msm_camera_io_w(val, vfe_dev->vfe_base + 0x494);
ISP_DBG("%s:camif PERIOD %x PATTERN %x\n",
__func__, subsample_period, subsample_pattern);
@@ -1508,16 +1521,19 @@ void msm_vfe47_configure_hvx(struct vfe_device *vfe_dev,
pr_err("%s: no stream_clk\n", __func__);
return;
}
- rc = msm_camera_clk_enable(&vfe_dev->pdev->dev, vfe_dev->hvx_clk_info,
- vfe_dev->hvx_clk, vfe_dev->num_hvx_clk, is_stream_on);
- if (rc) {
- pr_err("%s: stream_clk enable failed, enable: %u\n",
- __func__,
- is_stream_on);
- return;
- }
- if (is_stream_on == 1) {
+ if (is_stream_on) {
/* Enable HVX */
+ if (!vfe_dev->hvx_clk_state) {
+ rc = msm_camera_clk_enable(&vfe_dev->pdev->dev,
+ vfe_dev->hvx_clk_info, vfe_dev->hvx_clk,
+ vfe_dev->num_hvx_clk, is_stream_on);
+ if (rc) {
+ pr_err("%s: stream_clk enable failed\n",
+ __func__);
+ return;
+ }
+ vfe_dev->hvx_clk_state = true;
+ }
val = msm_camera_io_r(vfe_dev->vfe_base + 0x50);
val |= (1 << 3);
msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x50);
@@ -1527,6 +1543,17 @@ void msm_vfe47_configure_hvx(struct vfe_device *vfe_dev,
msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x50);
} else {
/* Disable HVX */
+ if (!vfe_dev->hvx_clk_state)
+ return;
+ rc = msm_camera_clk_enable(&vfe_dev->pdev->dev,
+ vfe_dev->hvx_clk_info, vfe_dev->hvx_clk,
+ vfe_dev->num_hvx_clk, is_stream_on);
+ if (rc) {
+ pr_err("%s: stream_clk disable failed\n",
+ __func__);
+ return;
+ }
+ vfe_dev->hvx_clk_state = false;
val = msm_camera_io_r(vfe_dev->vfe_base + 0x50);
val &= 0xFFFFFFF7;
msm_camera_io_w_mb(val, vfe_dev->vfe_base + 0x50);
@@ -1895,7 +1922,7 @@ void msm_vfe47_update_ping_pong_addr(
if (buf_size < 0)
buf_size = 0;
- paddr32_max = (paddr + buf_size) & 0xFFFFFFC0;
+ paddr32_max = (paddr + buf_size) & 0xFFFFFFE0;
msm_camera_io_w(paddr32, vfe_base +
VFE47_PING_PONG_BASE(wm_idx, pingpong_bit));
@@ -2383,18 +2410,23 @@ void msm_vfe47_stats_enable_module(struct vfe_device *vfe_dev,
void msm_vfe47_stats_update_ping_pong_addr(
struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info,
- uint32_t pingpong_status, dma_addr_t paddr)
+ uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_size)
{
void __iomem *vfe_base = vfe_dev->vfe_base;
int vfe_idx = msm_isp_get_vfe_idx_for_stats_stream(vfe_dev,
stream_info);
uint32_t paddr32 = (paddr & 0xFFFFFFFF);
+ uint32_t paddr32_max;
int stats_idx;
stats_idx = STATS_IDX(stream_info->stream_handle[vfe_idx]);
msm_camera_io_w(paddr32, vfe_base +
VFE47_STATS_PING_PONG_BASE(stats_idx, pingpong_status));
+
+ paddr32_max = (paddr + buf_size) & 0xFFFFFFE0;
+ msm_camera_io_w(paddr32_max, vfe_base +
+ VFE47_STATS_PING_PONG_BASE(stats_idx, pingpong_status) + 0x4);
}
uint32_t msm_vfe47_stats_get_wm_mask(
@@ -2528,6 +2560,7 @@ int msm_vfe47_get_clks(struct vfe_device *vfe_dev)
vfe_dev->hvx_clk_info =
&vfe_dev->vfe_clk_info[vfe_dev->num_clk-1];
vfe_dev->hvx_clk = &vfe_dev->vfe_clk[vfe_dev->num_clk-1];
+ vfe_dev->hvx_clk_state = false;
}
for (i = 0; i < vfe_dev->num_clk; i++) {
@@ -2553,8 +2586,8 @@ void msm_vfe47_put_clks(struct vfe_device *vfe_dev)
int msm_vfe47_enable_clks(struct vfe_device *vfe_dev, int enable)
{
return msm_camera_clk_enable(&vfe_dev->pdev->dev,
- vfe_dev->vfe_clk_info,
- vfe_dev->vfe_clk, vfe_dev->num_norm_clk, enable);
+ vfe_dev->vfe_clk_info,
+ vfe_dev->vfe_clk, vfe_dev->num_norm_clk, enable);
}
int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate)
@@ -2565,17 +2598,19 @@ int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate)
long clk_rate, prev_clk_rate;
clk_rate = clk_round_rate(vfe_dev->vfe_clk[clk_idx], *rate);
- if (vfe_dev->msm_isp_vfe_clk_rate == clk_rate)
+ if (vfe_dev->vfe_clk_info[clk_idx].clk_rate == clk_rate)
return rc;
- prev_clk_rate = vfe_dev->msm_isp_vfe_clk_rate;
- vfe_dev->msm_isp_vfe_clk_rate = clk_rate;
+ prev_clk_rate =
+ vfe_dev->vfe_clk_info[clk_idx].clk_rate;
+ vfe_dev->vfe_clk_info[clk_idx].clk_rate =
+ clk_rate;
/*
* if cx_ipeak is supported vote first so that dsp throttling is
* reduced before we go to turbo
*/
if ((vfe_dev->vfe_cx_ipeak) &&
- (vfe_dev->msm_isp_vfe_clk_rate >=
+ (vfe_dev->vfe_clk_info[clk_idx].clk_rate >=
vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_NOMINAL]
[vfe_dev->hw_info->vfe_clk_idx]) &&
prev_clk_rate <
@@ -2598,7 +2633,7 @@ int msm_vfe47_set_clk_rate(struct vfe_device *vfe_dev, long *rate)
* if voting done earlier
*/
if ((vfe_dev->vfe_cx_ipeak) &&
- (vfe_dev->msm_isp_vfe_clk_rate <
+ (vfe_dev->vfe_clk_info[clk_idx].clk_rate <
vfe_dev->vfe_clk_rates[MSM_VFE_CLK_RATE_NOMINAL]
[vfe_dev->hw_info->vfe_clk_idx]) &&
prev_clk_rate >=
@@ -2915,6 +2950,7 @@ struct msm_vfe_hardware_info vfe47_hw_info = {
.process_epoch_irq = msm_vfe47_process_epoch_irq,
.config_irq = msm_vfe47_config_irq,
.read_irq_status = msm_vfe47_read_irq_status,
+ .preprocess_camif_irq = msm_isp47_preprocess_camif_irq,
},
.axi_ops = {
.reload_wm = msm_vfe47_axi_reload_wm,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h
index 22a1a21bce9a..60afe3a80091 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-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
@@ -42,6 +42,8 @@ void msm_vfe47_process_reg_update(struct vfe_device *vfe_dev,
void msm_vfe47_process_epoch_irq(struct vfe_device *vfe_dev,
uint32_t irq_status0, uint32_t irq_status1,
struct msm_isp_timestamp *ts);
+void msm_isp47_preprocess_camif_irq(struct vfe_device *vfe_dev,
+ uint32_t irq_status0);
void msm_vfe47_reg_update(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src);
long msm_vfe47_reset_hardware(struct vfe_device *vfe_dev,
@@ -148,7 +150,7 @@ void msm_vfe47_stats_enable_module(struct vfe_device *vfe_dev,
uint32_t stats_mask, uint8_t enable);
void msm_vfe47_stats_update_ping_pong_addr(
struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *stream_info,
- uint32_t pingpong_status, dma_addr_t paddr);
+ uint32_t pingpong_status, dma_addr_t paddr, uint32_t buf_size);
uint32_t msm_vfe47_stats_get_wm_mask(
uint32_t irq_status0, uint32_t irq_status1);
uint32_t msm_vfe47_stats_get_comp_mask(
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
index 5b4d6aa63055..e3d8ecb410ff 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp48.c
@@ -237,6 +237,7 @@ static int msm_vfe48_get_clks(struct vfe_device *vfe_dev)
vfe_dev->hvx_clk_info =
&vfe_dev->vfe_clk_info[vfe_dev->num_clk-1];
vfe_dev->hvx_clk = &vfe_dev->vfe_clk[vfe_dev->num_clk-1];
+ vfe_dev->hvx_clk_state = false;
}
for (i = 0; i < vfe_dev->num_clk; i++) {
@@ -368,6 +369,7 @@ struct msm_vfe_hardware_info vfe48_hw_info = {
.process_stats_irq = msm_isp_process_stats_irq,
.process_epoch_irq = msm_vfe47_process_epoch_irq,
.config_irq = msm_vfe47_config_irq,
+ .preprocess_camif_irq = msm_isp47_preprocess_camif_irq,
},
.axi_ops = {
.reload_wm = msm_vfe47_axi_reload_wm,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index 8488405b561a..ebd3a32281d7 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -948,6 +948,8 @@ static void msm_isp_update_pd_stats_idx(struct vfe_device *vfe_dev,
uint32_t pingpong_status = 0, pingpong_bit = 0;
struct msm_isp_buffer *done_buf = NULL;
int vfe_idx = -1;
+ /* initialize pd_buf_idx with an invalid index 0xF */
+ vfe_dev->pd_buf_idx = 0xF;
if (frame_src < VFE_RAW_0 || frame_src > VFE_RAW_2)
return;
@@ -1134,7 +1136,8 @@ static void msm_isp_calculate_bandwidth(
axi_data = &vfe_dev->axi_data;
if (stream_info->stream_src < RDI_INTF_0) {
stream_info->bandwidth[i] =
- (vfe_dev->msm_isp_vfe_clk_rate /
+ (vfe_dev->vfe_clk_info[
+ vfe_dev->hw_info->vfe_clk_idx].clk_rate /
axi_data->src_info[VFE_PIX_0].width) *
stream_info->max_width[i];
stream_info->bandwidth[i] =
@@ -1147,7 +1150,9 @@ static void msm_isp_calculate_bandwidth(
stream_info->output_format);
if (rdi < VFE_SRC_MAX) {
stream_info->bandwidth[i] =
- (vfe_dev->msm_isp_vfe_clk_rate / 8) * bpp;
+ (vfe_dev->vfe_clk_info[
+ vfe_dev->hw_info->vfe_clk_idx].clk_rate /
+ 8) * bpp;
} else {
pr_err("%s: Invalid rdi interface\n", __func__);
}
@@ -1171,7 +1176,7 @@ void msm_isp_get_avtimer_ts(
rc = avcs_core_query_timer(&avtimer_tick);
if (rc < 0) {
- pr_err("%s: Error: Invalid AVTimer Tick, rc=%d\n",
+ pr_err_ratelimited("%s: Error: Invalid AVTimer Tick, rc=%d\n",
__func__, rc);
/* In case of error return zero AVTimer Tick Value */
time_stamp->vt_time.tv_sec = 0;
@@ -2439,7 +2444,7 @@ int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg)
total_bandwidth +=
stream_info->bandwidth[
vfe_idx];
- stream_info->state = PAUSING;
+ stream_info->state = PAUSED;
}
spin_unlock_irqrestore(&stream_info->lock, flags);
}
@@ -2453,7 +2458,7 @@ int msm_isp_ab_ib_update_lpm_mode(struct vfe_device *vfe_dev, void *arg)
msm_isp_get_stream_common_data(vfe_dev,
ab_ib_vote->stream_src[i]);
spin_lock_irqsave(&stream_info->lock, flags);
- if (stream_info->state == PAUSING) {
+ if (stream_info->state == PAUSED) {
vfe_idx =
msm_isp_get_vfe_idx_for_stream(vfe_dev,
stream_info);
@@ -2811,6 +2816,7 @@ static int __msm_isp_check_stream_state(struct msm_vfe_axi_stream *stream_info,
case RESUMING:
case RESUME_PENDING:
case ACTIVE:
+ case PAUSED:
if (cmd != 0)
return -EALREADY;
break;
@@ -2877,9 +2883,11 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev,
* those state transitions instead of directly forcing stream to
* be INACTIVE
*/
- while (stream_info->state != ACTIVE)
- __msm_isp_axi_stream_update(stream_info,
+ if (stream_info->state != PAUSED) {
+ while (stream_info->state != ACTIVE)
+ __msm_isp_axi_stream_update(stream_info,
&timestamp);
+ }
msm_isp_cfg_stream_scratch(stream_info, VFE_PING_FLAG);
msm_isp_cfg_stream_scratch(stream_info, VFE_PONG_FLAG);
stream_info->undelivered_request_cnt = 0;
@@ -2892,8 +2900,15 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev,
vfe_dev->hw_info->vfe_ops.axi_ops.
clear_wm_irq_mask(vfe_dev, stream_info);
}
- init_completion(&stream_info->inactive_comp);
- stream_info->state = STOP_PENDING;
+ if (stream_info->state == ACTIVE) {
+ init_completion(&stream_info->inactive_comp);
+ stream_info->state = STOP_PENDING;
+ } else if (stream_info->state == PAUSED) {
+ /* don't wait for reg update */
+ stream_info->state = STOP_PENDING;
+ msm_isp_axi_stream_enable_cfg(stream_info);
+ stream_info->state = INACTIVE;
+ }
spin_unlock_irqrestore(&stream_info->lock, flags);
}
@@ -3321,6 +3336,7 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
int k;
uint32_t wm_mask = 0;
int vfe_idx;
+ uint32_t pingpong_bit = 0;
if (!vfe_dev || !stream_info) {
pr_err("%s %d failed: vfe_dev %pK stream_info %pK\n", __func__,
@@ -3339,27 +3355,40 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
}
frame_src = SRC_TO_INTF(stream_info->stream_src);
+ pingpong_status = vfe_dev->hw_info->
+ vfe_ops.axi_ops.get_pingpong_status(vfe_dev);
/*
* If PIX stream is active then RDI path uses SOF frame ID of PIX
* In case of standalone RDI streaming, SOF are used from
* individual intf.
*/
- if (((vfe_dev->axi_data.src_info[VFE_PIX_0].active) && (frame_id <=
- vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id)) ||
- ((!vfe_dev->axi_data.src_info[VFE_PIX_0].active) && (frame_id <=
- vfe_dev->axi_data.src_info[frame_src].frame_id)) ||
- stream_info->undelivered_request_cnt >= MAX_BUFFERS_IN_HW) {
- pr_debug("%s:%d invalid request_frame %d cur frame id %d pix %d\n",
+ /*
+ * If frame_id = 1 then no eof check is needed
+ */
+ if (vfe_dev->axi_data.src_info[VFE_PIX_0].active &&
+ vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame == false) {
+ pr_debug("%s:%d invalid time to request frame %d\n",
+ __func__, __LINE__, frame_id);
+ goto error;
+ }
+ if ((vfe_dev->axi_data.src_info[VFE_PIX_0].active && (frame_id !=
+ vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id + vfe_dev->
+ axi_data.src_info[VFE_PIX_0].sof_counter_step)) ||
+ ((!vfe_dev->axi_data.src_info[VFE_PIX_0].active) && (frame_id !=
+ vfe_dev->axi_data.src_info[frame_src].frame_id + vfe_dev->
+ axi_data.src_info[frame_src].sof_counter_step))) {
+ pr_debug("%s:%d invalid frame id %d cur frame id %d pix %d\n",
__func__, __LINE__, frame_id,
vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id,
vfe_dev->axi_data.src_info[VFE_PIX_0].active);
-
- rc = msm_isp_return_empty_buffer(vfe_dev, stream_info,
- user_stream_id, frame_id, buf_index, frame_src);
- if (rc < 0)
- pr_err("%s:%d failed: return_empty_buffer src %d\n",
- __func__, __LINE__, frame_src);
- return 0;
+ goto error;
+ }
+ if (stream_info->undelivered_request_cnt >= MAX_BUFFERS_IN_HW) {
+ pr_debug("%s:%d invalid undelivered_request_cnt %d frame id %d\n",
+ __func__, __LINE__,
+ stream_info->undelivered_request_cnt,
+ vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id);
+ goto error;
}
if ((frame_src == VFE_PIX_0) && !stream_info->undelivered_request_cnt &&
MSM_VFE_STREAM_STOP_PERIOD !=
@@ -3381,6 +3410,25 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
}
spin_lock_irqsave(&stream_info->lock, flags);
+ vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
+ if (stream_info->undelivered_request_cnt == 1) {
+ pingpong_status =
+ vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(
+ vfe_dev);
+ pingpong_bit = ((pingpong_status >>
+ stream_info->wm[vfe_idx][0]) & 0x1);
+ if (stream_info->sw_ping_pong_bit == !pingpong_bit) {
+ ISP_DBG("%s:Return Empty Buffer stream id 0x%X\n",
+ __func__, stream_info->stream_id);
+ rc = msm_isp_return_empty_buffer(vfe_dev, stream_info,
+ user_stream_id, frame_id, buf_index,
+ frame_src);
+ spin_unlock_irqrestore(&stream_info->lock,
+ flags);
+ return 0;
+ }
+ }
+
queue_req = &stream_info->request_queue_cmd[stream_info->request_q_idx];
if (queue_req->cmd_used) {
spin_unlock_irqrestore(&stream_info->lock, flags);
@@ -3410,7 +3458,6 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
stream_info->request_q_cnt++;
stream_info->undelivered_request_cnt++;
- vfe_idx = msm_isp_get_vfe_idx_for_stream(vfe_dev, stream_info);
stream_cfg_cmd.axi_stream_handle = stream_info->stream_handle[vfe_idx];
stream_cfg_cmd.frame_skip_pattern = NO_SKIP;
stream_cfg_cmd.init_frame_drop = 0;
@@ -3439,9 +3486,6 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
}
stream_info->sw_ping_pong_bit = 0;
} else if (stream_info->undelivered_request_cnt == 2) {
- pingpong_status =
- vfe_dev->hw_info->vfe_ops.axi_ops.get_pingpong_status(
- vfe_dev);
rc = msm_isp_cfg_ping_pong_address(
stream_info, pingpong_status);
if (rc) {
@@ -3467,6 +3511,14 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev,
spin_unlock_irqrestore(&stream_info->lock, flags);
return rc;
+error:
+ rc = msm_isp_return_empty_buffer(vfe_dev, stream_info,
+ user_stream_id, frame_id, buf_index, frame_src);
+ if (rc < 0)
+ pr_err("%s:%d failed: return_empty_buffer src %d\n",
+ __func__, __LINE__, frame_src);
+ return 0;
+
}
static int msm_isp_add_buf_queue(struct vfe_device *vfe_dev,
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index 66292acb5ef3..f2cf4d477b3f 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -23,7 +23,8 @@ static inline void msm_isp_stats_cfg_wm_scratch(struct vfe_device *vfe_dev,
{
vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr(
vfe_dev, stream_info,
- pingpong_status, vfe_dev->buf_mgr->scratch_buf_stats_addr);
+ pingpong_status, vfe_dev->buf_mgr->scratch_buf_stats_addr,
+ SZ_32M);
}
static inline void msm_isp_stats_cfg_stream_scratch(
@@ -123,7 +124,8 @@ static int msm_isp_stats_cfg_ping_pong_address(
vfe_dev->hw_info->vfe_ops.stats_ops.update_ping_pong_addr(
vfe_dev, stream_info, pingpong_status,
buf->mapped_info[0].paddr +
- stream_info->buffer_offset[k]);
+ stream_info->buffer_offset[k],
+ buf->mapped_info[0].len);
}
stream_info->buf[pingpong_bit] = buf;
buf->pingpong_bit = pingpong_bit;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 2927fb851a06..765bf6521759 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -166,7 +166,8 @@ void msm_isp_util_get_bandwidth_stats(struct vfe_device *vfe_dev,
stats->isp_cpp_ib = isp_bandwidth_mgr.client_info[ISP_CPP].ib;
stats->last_overflow_ab = vfe_dev->msm_isp_last_overflow_ab;
stats->last_overflow_ib = vfe_dev->msm_isp_last_overflow_ib;
- stats->vfe_clk_rate = vfe_dev->msm_isp_vfe_clk_rate;
+ stats->vfe_clk_rate = vfe_dev->vfe_clk_info[
+ vfe_dev->hw_info->vfe_clk_idx].clk_rate;
stats->cpp_clk_rate = msm_isp_cpp_clk_rate;
}
@@ -538,7 +539,8 @@ int msm_isp_cfg_input(struct vfe_device *vfe_dev, void *arg)
* Only set rate to higher, do not lower higher
* rate needed by another input
*/
- if (pixel_clock > vfe_dev->msm_isp_vfe_clk_rate) {
+ if (pixel_clock > vfe_dev->vfe_clk_info[
+ vfe_dev->hw_info->vfe_clk_idx].clk_rate) {
rc = vfe_dev->hw_info->vfe_ops.platform_ops.set_clk_rate(
vfe_dev,
&pixel_clock);
@@ -2056,13 +2058,19 @@ static void msm_isp_enqueue_tasklet_cmd(struct vfe_device *vfe_dev,
{
unsigned long flags;
struct msm_vfe_tasklet_queue_cmd *queue_cmd = NULL;
+ struct msm_vfe_tasklet *tasklet;
- spin_lock_irqsave(&vfe_dev->tasklet_lock, flags);
- queue_cmd = &vfe_dev->tasklet_queue_cmd[vfe_dev->taskletq_idx];
+ if (vfe_dev->is_split)
+ tasklet = &vfe_dev->common_data->tasklets[MAX_VFE];
+ else
+ tasklet = &vfe_dev->common_data->tasklets[vfe_dev->pdev->id];
+
+ spin_lock_irqsave(&tasklet->tasklet_lock, flags);
+ queue_cmd = &tasklet->tasklet_queue_cmd[tasklet->taskletq_idx];
if (queue_cmd->cmd_used) {
- ISP_DBG("%s: Tasklet queue overflow: %d\n",
+ pr_err("%s: Tasklet queue overflow: %d\n",
__func__, vfe_dev->pdev->id);
- list_del(&queue_cmd->list);
+ return;
} else {
atomic_add(1, &vfe_dev->irq_cnt);
}
@@ -2071,11 +2079,13 @@ static void msm_isp_enqueue_tasklet_cmd(struct vfe_device *vfe_dev,
msm_isp_get_timestamp(&queue_cmd->ts, vfe_dev);
queue_cmd->cmd_used = 1;
- vfe_dev->taskletq_idx = (vfe_dev->taskletq_idx + 1) %
+ queue_cmd->vfe_dev = vfe_dev;
+
+ tasklet->taskletq_idx = (tasklet->taskletq_idx + 1) %
MSM_VFE_TASKLETQ_SIZE;
- list_add_tail(&queue_cmd->list, &vfe_dev->tasklet_q);
- spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags);
- tasklet_schedule(&vfe_dev->vfe_tasklet);
+ list_add_tail(&queue_cmd->list, &tasklet->tasklet_q);
+ spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
+ tasklet_schedule(&tasklet->tasklet);
}
irqreturn_t msm_isp_process_irq(int irq_num, void *data)
@@ -2092,7 +2102,10 @@ irqreturn_t msm_isp_process_irq(int irq_num, void *data)
__func__, vfe_dev->pdev->id);
return IRQ_HANDLED;
}
-
+ if (vfe_dev->hw_info->vfe_ops.irq_ops.preprocess_camif_irq) {
+ vfe_dev->hw_info->vfe_ops.irq_ops.preprocess_camif_irq(
+ vfe_dev, irq_status0);
+ }
if (msm_isp_process_overflow_irq(vfe_dev,
&irq_status0, &irq_status1, 0)) {
/* if overflow initiated no need to handle the interrupts */
@@ -2124,39 +2137,39 @@ irqreturn_t msm_isp_process_irq(int irq_num, void *data)
void msm_isp_do_tasklet(unsigned long data)
{
unsigned long flags;
- struct vfe_device *vfe_dev = (struct vfe_device *) data;
- struct msm_vfe_irq_ops *irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops;
+ struct msm_vfe_tasklet *tasklet = (struct msm_vfe_tasklet *)data;
+ struct vfe_device *vfe_dev;
+ struct msm_vfe_irq_ops *irq_ops;
struct msm_vfe_tasklet_queue_cmd *queue_cmd;
struct msm_isp_timestamp ts;
uint32_t irq_status0, irq_status1;
- if (vfe_dev->vfe_base == NULL || vfe_dev->vfe_open_cnt == 0) {
- ISP_DBG("%s: VFE%d open cnt = %d, device closed(base = %pK)\n",
- __func__, vfe_dev->pdev->id, vfe_dev->vfe_open_cnt,
- vfe_dev->vfe_base);
- return;
- }
-
- while (atomic_read(&vfe_dev->irq_cnt)) {
- spin_lock_irqsave(&vfe_dev->tasklet_lock, flags);
- queue_cmd = list_first_entry_or_null(&vfe_dev->tasklet_q,
- struct msm_vfe_tasklet_queue_cmd, list);
+ while (1) {
+ spin_lock_irqsave(&tasklet->tasklet_lock, flags);
+ queue_cmd = list_first_entry_or_null(&tasklet->tasklet_q,
+ struct msm_vfe_tasklet_queue_cmd, list);
if (!queue_cmd) {
- atomic_set(&vfe_dev->irq_cnt, 0);
- spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags);
- return;
+ spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
+ break;
}
- atomic_sub(1, &vfe_dev->irq_cnt);
- list_del(&queue_cmd->list);
+ list_del_init(&queue_cmd->list);
+ vfe_dev = queue_cmd->vfe_dev;
queue_cmd->cmd_used = 0;
+ queue_cmd->vfe_dev = NULL;
irq_status0 = queue_cmd->vfeInterruptStatus0;
irq_status1 = queue_cmd->vfeInterruptStatus1;
ts = queue_cmd->ts;
- spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags);
+ spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
+ if (vfe_dev->vfe_open_cnt == 0) {
+ pr_err("%s: VFE%d open cnt = %d, irq %x/%x\n",
+ __func__, vfe_dev->pdev->id, vfe_dev->vfe_open_cnt,
+ irq_status0, irq_status1);
+ continue;
+ }
+ atomic_sub(1, &vfe_dev->irq_cnt);
msm_isp_prepare_tasklet_debug_info(vfe_dev,
irq_status0, irq_status1, ts);
- ISP_DBG("%s: vfe_id %d status0: 0x%x status1: 0x%x\n",
- __func__, vfe_dev->pdev->id, irq_status0, irq_status1);
+ irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops;
irq_ops->process_reset_irq(vfe_dev,
irq_status0, irq_status1);
irq_ops->process_halt_irq(vfe_dev,
@@ -2297,7 +2310,6 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
sizeof(vfe_dev->fetch_engine_info));
vfe_dev->axi_data.hw_info = vfe_dev->hw_info->axi_hw_info;
vfe_dev->axi_data.enable_frameid_recovery = 0;
- vfe_dev->taskletq_idx = 0;
vfe_dev->vt_enable = 0;
vfe_dev->reg_update_requested = 0;
/* Register page fault handler */
@@ -2362,15 +2374,14 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
update_camif_state(vfe_dev, DISABLE_CAMIF_IMMEDIATELY);
vfe_dev->hw_info->vfe_ops.core_ops.reset_hw(vfe_dev, 0, 0);
- /* after regular hw stop, reduce open cnt */
- vfe_dev->vfe_open_cnt--;
-
/* put scratch buf in all the wm */
for (wm = 0; wm < vfe_dev->axi_data.hw_info->num_wm; wm++) {
msm_isp_cfg_wm_scratch(vfe_dev, wm, VFE_PING_FLAG);
msm_isp_cfg_wm_scratch(vfe_dev, wm, VFE_PONG_FLAG);
}
vfe_dev->hw_info->vfe_ops.core_ops.release_hw(vfe_dev);
+ /* after regular hw stop, reduce open cnt */
+ vfe_dev->vfe_open_cnt--;
vfe_dev->buf_mgr->ops->buf_mgr_deinit(vfe_dev->buf_mgr);
if (vfe_dev->vt_enable) {
msm_isp_end_avtimer();
@@ -2387,22 +2398,27 @@ int msm_isp_close_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
void msm_isp_flush_tasklet(struct vfe_device *vfe_dev)
{
unsigned long flags;
- struct msm_vfe_tasklet_queue_cmd *queue_cmd;
+ int i;
+ struct msm_vfe_tasklet_queue_cmd *queue_cmd, *q_cmd_next;
+ struct msm_vfe_tasklet *tasklet;
- spin_lock_irqsave(&vfe_dev->tasklet_lock, flags);
- while (atomic_read(&vfe_dev->irq_cnt)) {
- queue_cmd = list_first_entry(&vfe_dev->tasklet_q,
- struct msm_vfe_tasklet_queue_cmd, list);
- if (!queue_cmd) {
- atomic_set(&vfe_dev->irq_cnt, 0);
- break;
+ for (i = 0; i <= MAX_VFE; i++) {
+ if (i != vfe_dev->pdev->id &&
+ i != MAX_VFE)
+ continue;
+ tasklet = &vfe_dev->common_data->tasklets[i];
+ spin_lock_irqsave(&tasklet->tasklet_lock, flags);
+ list_for_each_entry_safe(queue_cmd, q_cmd_next,
+ &tasklet->tasklet_q, list) {
+ if (queue_cmd->vfe_dev != vfe_dev)
+ continue;
+ list_del_init(&queue_cmd->list);
+ queue_cmd->cmd_used = 0;
}
- atomic_sub(1, &vfe_dev->irq_cnt);
- list_del(&queue_cmd->list);
- queue_cmd->cmd_used = 0;
+ spin_unlock_irqrestore(&tasklet->tasklet_lock, flags);
+ tasklet_kill(&tasklet->tasklet);
}
- spin_unlock_irqrestore(&vfe_dev->tasklet_lock, flags);
- tasklet_kill(&vfe_dev->vfe_tasklet);
+ atomic_set(&vfe_dev->irq_cnt, 0);
return;
}
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 9d52107c9993..41d8ef577a27 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -73,7 +73,7 @@ static void msm_ispif_io_dump_reg(struct ispif_device *ispif)
static inline int msm_ispif_is_intf_valid(uint32_t csid_version,
- uint8_t intf_type)
+ enum msm_ispif_vfe_intf intf_type)
{
return ((csid_version <= CSID_VERSION_V22 && intf_type != VFE0) ||
(intf_type >= VFE_MAX)) ? false : true;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
index 92b6e8ffa92e..76a4f1e39837 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.c
@@ -477,6 +477,7 @@ static int sde_mdp_parse_dt_misc(struct platform_device *pdev,
{
int rc;
u32 data;
+ struct device_node *node;
rc = of_property_read_u32(pdev->dev.of_node, "qcom,mdss-rot-block-size",
&data);
@@ -505,6 +506,19 @@ static int sde_mdp_parse_dt_misc(struct platform_device *pdev,
mdata->mdp_base = mdata->sde_io.base + SDE_MDP_OFFSET;
+ node = of_get_child_by_name(pdev->dev.of_node,
+ "qcom,sde-reg-bus");
+ if (node) {
+ mdata->reg_bus_pdata = msm_bus_pdata_from_node(pdev, node);
+ if (IS_ERR_OR_NULL(mdata->reg_bus_pdata)) {
+ SDEROT_DBG("bus_pdata reg_bus failed\n");
+ mdata->reg_bus_pdata = NULL;
+ }
+ } else {
+ SDEROT_DBG("sde-reg-bus not found\n");
+ mdata->reg_bus_pdata = NULL;
+ }
+
return 0;
}
@@ -553,9 +567,10 @@ static int sde_mdp_bus_scale_register(struct sde_rot_data_type *mdata)
if (!mdata->reg_bus_hdl) {
/* Continue without reg_bus scaling */
SDEROT_WARN("reg_bus_client register failed\n");
- } else
+ } else {
SDEROT_DBG("register reg_bus_hdl=%x\n",
mdata->reg_bus_hdl);
+ }
}
return 0;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
index 9ba0b7d93616..d68ff4fde306 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_base.h
@@ -195,6 +195,7 @@ struct sde_rot_data_type {
struct ion_client *iclient;
bool handoff_done;
+ struct msm_bus_scale_pdata *reg_bus_pdata;
};
int sde_rotator_base_init(struct sde_rot_data_type **pmdata,
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
index 1e85923c20b1..442e80e7100e 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c
@@ -2419,6 +2419,7 @@ static int sde_rotator_parse_dt_bus(struct sde_rot_mgr *mgr,
{
int ret = 0, i;
int usecases;
+ struct sde_rot_data_type *mdata = sde_rot_get_mdata();
mgr->data_bus.bus_scale_pdata = msm_bus_cl_get_pdata(dev);
if (IS_ERR_OR_NULL(mgr->data_bus.bus_scale_pdata)) {
@@ -2431,12 +2432,16 @@ static int sde_rotator_parse_dt_bus(struct sde_rot_mgr *mgr,
}
}
- mgr->reg_bus.bus_scale_pdata = &rot_reg_bus_scale_table;
- usecases = mgr->reg_bus.bus_scale_pdata->num_usecases;
- for (i = 0; i < usecases; i++) {
- rot_reg_bus_usecases[i].num_paths = 1;
- rot_reg_bus_usecases[i].vectors =
- &rot_reg_bus_vectors[i];
+ if (mdata && mdata->reg_bus_pdata) {
+ mgr->reg_bus.bus_scale_pdata = mdata->reg_bus_pdata;
+ } else {
+ mgr->reg_bus.bus_scale_pdata = &rot_reg_bus_scale_table;
+ usecases = mgr->reg_bus.bus_scale_pdata->num_usecases;
+ for (i = 0; i < usecases; i++) {
+ rot_reg_bus_usecases[i].num_paths = 1;
+ rot_reg_bus_usecases[i].vectors =
+ &rot_reg_bus_vectors[i];
+ }
}
return ret;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index e170c9ffafc7..0cd8e613c224 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -1924,8 +1924,13 @@ static long sde_rotator_private_ioctl(struct file *file, void *fh,
static long sde_rotator_compat_ioctl32(struct file *file,
unsigned int cmd, unsigned long arg)
{
+ struct video_device *vdev = video_devdata(file);
+ struct sde_rotator_ctx *ctx =
+ sde_rotator_ctx_from_fh(file->private_data);
long ret;
+ mutex_lock(vdev->lock);
+
switch (cmd) {
case VIDIOC_S_SDE_ROTATOR_FENCE:
case VIDIOC_G_SDE_ROTATOR_FENCE:
@@ -1934,14 +1939,14 @@ static long sde_rotator_compat_ioctl32(struct file *file,
if (copy_from_user(&fence, (void __user *)arg,
sizeof(struct msm_sde_rotator_fence)))
- return -EFAULT;
+ goto ioctl32_error;
ret = sde_rotator_private_ioctl(file, file->private_data,
0, cmd, (void *)&fence);
if (copy_to_user((void __user *)arg, &fence,
sizeof(struct msm_sde_rotator_fence)))
- return -EFAULT;
+ goto ioctl32_error;
break;
}
@@ -1952,24 +1957,31 @@ static long sde_rotator_compat_ioctl32(struct file *file,
if (copy_from_user(&comp_ratio, (void __user *)arg,
sizeof(struct msm_sde_rotator_comp_ratio)))
- return -EFAULT;
+ goto ioctl32_error;
ret = sde_rotator_private_ioctl(file, file->private_data,
0, cmd, (void *)&comp_ratio);
if (copy_to_user((void __user *)arg, &comp_ratio,
sizeof(struct msm_sde_rotator_comp_ratio)))
- return -EFAULT;
+ goto ioctl32_error;
break;
}
default:
+ SDEDEV_ERR(ctx->rot_dev->dev, "invalid ioctl32 type:%x\n", cmd);
ret = -ENOIOCTLCMD;
break;
}
+ mutex_unlock(vdev->lock);
return ret;
+
+ioctl32_error:
+ mutex_unlock(vdev->lock);
+ SDEDEV_ERR(ctx->rot_dev->dev, "error handling ioctl32 cmd:%x\n", cmd);
+ return -EFAULT;
}
#endif
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index 2c79ad7e45be..c3a0cfb390c4 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -1600,6 +1600,7 @@ static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw,
u32 safe_lut = 0; /* applicable for realtime client only */
u32 flags = 0;
u32 rststs = 0;
+ u32 reg = 0;
struct sde_rotation_item *item;
if (!hw || !entry) {
@@ -1836,10 +1837,10 @@ static int sde_hw_rotator_config(struct sde_rot_hw_resource *hw,
/* Enable write gather for writeback to remove write gaps, which
* may hang AXI/BIMC/SDE.
*/
- if (!((mdata->mdss_version == MDSS_MDP_HW_REV_320) ||
- (mdata->mdss_version == MDSS_MDP_HW_REV_330)))
- SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN,
- BIT(mdata->vbif_xin_id[XIN_WRITEBACK]));
+
+ reg = SDE_VBIF_READ(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN);
+ SDE_VBIF_WRITE(mdata, MMSS_VBIF_NRT_VBIF_WRITE_GATHTER_EN,
+ reg | BIT(mdata->vbif_xin_id[XIN_WRITEBACK]));
if (mdata->vbif_reg_unlock)
mdata->vbif_reg_unlock();
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index c945e4c2fbd4..ec30a004f319 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -200,22 +200,30 @@ static int smsusb_start_streaming(struct smsusb_device_t *dev)
static int smsusb_sendrequest(void *context, void *buffer, size_t size)
{
struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
- struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer;
- int dummy;
+ struct sms_msg_hdr *phdr;
+ int dummy, ret;
if (dev->state != SMSUSB_ACTIVE) {
pr_debug("Device not active yet\n");
return -ENOENT;
}
+ phdr = kmalloc(size, GFP_KERNEL);
+ if (!phdr)
+ return -ENOMEM;
+ memcpy(phdr, buffer, size);
+
pr_debug("sending %s(%d) size: %d\n",
smscore_translate_msg(phdr->msg_type), phdr->msg_type,
phdr->msg_length);
smsendian_handle_tx_message((struct sms_msg_data *) phdr);
- smsendian_handle_message_header((struct sms_msg_hdr *)buffer);
- return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
- buffer, size, &dummy, 1000);
+ smsendian_handle_message_header((struct sms_msg_hdr *)phdr);
+ ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
+ phdr, size, &dummy, 1000);
+
+ kfree(phdr);
+ return ret;
}
static char *smsusb1_fw_lkup[] = {
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index cfb868a48b5f..ff6feff21e94 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -416,7 +416,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
nextbuf = NULL;
spin_unlock_irqrestore(&queue->irqlock, flags);
- buf->state = buf->error ? VB2_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
+ buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
diff --git a/drivers/mfd/wcd934x-regmap.c b/drivers/mfd/wcd934x-regmap.c
index fbaf05e58aff..e8ba1495de2b 100644
--- a/drivers/mfd/wcd934x-regmap.c
+++ b/drivers/mfd/wcd934x-regmap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1926,6 +1926,19 @@ static bool wcd934x_is_volatile_register(struct device *dev, unsigned int reg)
case WCD934X_ANA_MBHC_ELECT:
case WCD934X_ANA_MBHC_ZDET:
case WCD934X_ANA_MICB2:
+ case WCD934X_CODEC_RPM_CLK_MCLK_CFG:
+ case WCD934X_CLK_SYS_MCLK_PRG:
+ case WCD934X_CHIP_TIER_CTRL_EFUSE_CTL:
+ case WCD934X_ANA_BIAS:
+ case WCD934X_ANA_BUCK_CTL:
+ case WCD934X_ANA_RCO:
+ case WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL:
+ case WCD934X_CODEC_RPM_CLK_GATE:
+ case WCD934X_BIAS_VBG_FINE_ADJ:
+ case WCD934X_CODEC_CPR_SVS_CX_VDD:
+ case WCD934X_CODEC_CPR_SVS2_CX_VDD:
+ case WCD934X_CDC_TOP_TOP_CFG1:
+ case WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL:
return true;
}
diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c
index 460ffc79f566..33ec0c15efa6 100644
--- a/drivers/misc/hdcp.c
+++ b/drivers/misc/hdcp.c
@@ -97,11 +97,6 @@
*/
#define SLEEP_SET_HW_KEY_MS 220
-#define QSEECOM_ALIGN_SIZE 0x40
-#define QSEECOM_ALIGN_MASK (QSEECOM_ALIGN_SIZE - 1)
-#define QSEECOM_ALIGN(x)\
- ((x + QSEECOM_ALIGN_SIZE) & (~QSEECOM_ALIGN_MASK))
-
/* hdcp command status */
#define HDCP_SUCCESS 0
diff --git a/drivers/misc/qseecom_kernel.h b/drivers/misc/qseecom_kernel.h
index 8f981903c3a1..40426b749f60 100644
--- a/drivers/misc/qseecom_kernel.h
+++ b/drivers/misc/qseecom_kernel.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -19,7 +19,7 @@
#define QSEECOM_ALIGN_SIZE 0x40
#define QSEECOM_ALIGN_MASK (QSEECOM_ALIGN_SIZE - 1)
#define QSEECOM_ALIGN(x) \
- ((x + QSEECOM_ALIGN_SIZE) & (~QSEECOM_ALIGN_MASK))
+ ((x + QSEECOM_ALIGN_MASK) & (~QSEECOM_ALIGN_MASK))
/*
* struct qseecom_handle -
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 4567b7526469..542f1733d0dd 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -2032,10 +2032,10 @@ reinit:
err = mmc_select_hs400(card);
if (err)
goto free_card;
- } else if (mmc_card_hs(card)) {
+ } else {
/* Select the desired bus width optionally */
err = mmc_select_bus_width(card);
- if (!IS_ERR_VALUE(err)) {
+ if (!IS_ERR_VALUE(err) && mmc_card_hs(card)) {
err = mmc_select_hs_ddr(card);
if (err)
goto free_card;
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 7274a6d2cce0..2eaac11ec8ba 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -2736,14 +2736,15 @@ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type)
msm_host->offset;
unsigned long flags;
bool done = false;
- u32 io_sig_sts;
+ u32 io_sig_sts = SWITCHABLE_SIGNALLING_VOL;
spin_lock_irqsave(&host->lock, flags);
pr_debug("%s: %s: request %d curr_pwr_state %x curr_io_level %x\n",
mmc_hostname(host->mmc), __func__, req_type,
msm_host->curr_pwr_state, msm_host->curr_io_level);
- io_sig_sts = sdhci_msm_readl_relaxed(host,
- msm_host_offset->CORE_GENERICS);
+ if (!msm_host->mci_removed)
+ io_sig_sts = sdhci_msm_readl_relaxed(host,
+ msm_host_offset->CORE_GENERICS);
/*
* The IRQ for request type IO High/Low will be generated when -
@@ -3304,6 +3305,21 @@ static void sdhci_msm_cmdq_dump_debug_ram(struct sdhci_host *host)
pr_err("-------------------------\n");
}
+static void sdhci_msm_cache_debug_data(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ struct sdhci_msm_debug_data *cached_data = &msm_host->cached_data;
+
+ memcpy(&cached_data->copy_mmc, msm_host->mmc,
+ sizeof(struct mmc_host));
+ if (msm_host->mmc->card)
+ memcpy(&cached_data->copy_card, msm_host->mmc->card,
+ sizeof(struct mmc_card));
+ memcpy(&cached_data->copy_host, host,
+ sizeof(struct sdhci_host));
+}
+
void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -3316,6 +3332,7 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
u32 debug_reg[MAX_TEST_BUS] = {0};
u32 sts = 0;
+ sdhci_msm_cache_debug_data(host);
pr_info("----------- VENDOR REGISTER DUMP -----------\n");
if (host->cq_host)
sdhci_msm_cmdq_dump_debug_ram(host);
@@ -3897,8 +3914,8 @@ void sdhci_msm_pm_qos_cpu_init(struct sdhci_host *host,
group->req.type = PM_QOS_REQ_AFFINE_CORES;
cpumask_copy(&group->req.cpus_affine,
&msm_host->pdata->pm_qos_data.cpu_group_map.mask[i]);
- /* For initialization phase, set the performance mode latency */
- group->latency = latency[i].latency[SDHCI_PERFORMANCE_MODE];
+ /* We set default latency here for all pm_qos cpu groups. */
+ group->latency = PM_QOS_DEFAULT_VALUE;
pm_qos_add_request(&group->req, PM_QOS_CPU_DMA_LATENCY,
group->latency);
pr_info("%s (): voted for group #%d (mask=0x%lx) latency=%d (0x%p)\n",
diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h
index c26636198a22..2e4f2179378e 100644
--- a/drivers/mmc/host/sdhci-msm.h
+++ b/drivers/mmc/host/sdhci-msm.h
@@ -171,6 +171,12 @@ struct sdhci_msm_ice_data {
int state;
};
+struct sdhci_msm_debug_data {
+ struct mmc_host copy_mmc;
+ struct mmc_card copy_card;
+ struct sdhci_host copy_host;
+};
+
struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -186,6 +192,7 @@ struct sdhci_msm_host {
atomic_t clks_on; /* Set if clocks are enabled */
struct sdhci_msm_pltfm_data *pdata;
struct mmc_host *mmc;
+ struct sdhci_msm_debug_data cached_data;
struct sdhci_pltfm_data sdhci_msm_pdata;
u32 curr_pwr_state;
u32 curr_io_level;
diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c
index f9fa3fad728e..2051f28ddac6 100644
--- a/drivers/mtd/maps/pmcmsp-flash.c
+++ b/drivers/mtd/maps/pmcmsp-flash.c
@@ -139,15 +139,13 @@ static int __init init_msp_flash(void)
}
msp_maps[i].bankwidth = 1;
- msp_maps[i].name = kmalloc(7, GFP_KERNEL);
+ msp_maps[i].name = kstrndup(flash_name, 7, GFP_KERNEL);
if (!msp_maps[i].name) {
iounmap(msp_maps[i].virt);
kfree(msp_parts[i]);
goto cleanup_loop;
}
- msp_maps[i].name = strncpy(msp_maps[i].name, flash_name, 7);
-
for (j = 0; j < pcnt; j++) {
part_name[5] = '0' + i;
part_name[7] = '0' + j;
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f184fb5bd110..fe75c7d4372d 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -425,4 +425,6 @@ config FUJITSU_ES
source "drivers/net/hyperv/Kconfig"
+source "drivers/net/rmnet/Kconfig"
+
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 900b0c5320bb..3cb2c188ee3f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -70,3 +70,4 @@ obj-$(CONFIG_HYPERV_NET) += hyperv/
obj-$(CONFIG_NTB_NETDEV) += ntb_netdev.o
obj-$(CONFIG_FUJITSU_ES) += fjes/
+obj-$(CONFIG_RMNET) += rmnet/
diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c
index a731720f1d13..449b2a47f9a8 100644
--- a/drivers/net/can/usb/usb_8dev.c
+++ b/drivers/net/can/usb/usb_8dev.c
@@ -954,8 +954,8 @@ static int usb_8dev_probe(struct usb_interface *intf,
for (i = 0; i < MAX_TX_URBS; i++)
priv->tx_contexts[i].echo_index = MAX_TX_URBS;
- priv->cmd_msg_buffer = kzalloc(sizeof(struct usb_8dev_cmd_msg),
- GFP_KERNEL);
+ priv->cmd_msg_buffer = devm_kzalloc(&intf->dev, sizeof(struct usb_8dev_cmd_msg),
+ GFP_KERNEL);
if (!priv->cmd_msg_buffer)
goto cleanup_candev;
@@ -969,7 +969,7 @@ static int usb_8dev_probe(struct usb_interface *intf,
if (err) {
netdev_err(netdev,
"couldn't register CAN device: %d\n", err);
- goto cleanup_cmd_msg_buffer;
+ goto cleanup_candev;
}
err = usb_8dev_cmd_version(priv, &version);
@@ -990,9 +990,6 @@ static int usb_8dev_probe(struct usb_interface *intf,
cleanup_unregister_candev:
unregister_netdev(priv->netdev);
-cleanup_cmd_msg_buffer:
- kfree(priv->cmd_msg_buffer);
-
cleanup_candev:
free_candev(netdev);
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 25aba9886990..0e67145bc418 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -993,7 +993,7 @@ static void mvpp2_txq_inc_put(struct mvpp2_txq_pcpu *txq_pcpu,
txq_pcpu->buffs + txq_pcpu->txq_put_index;
tx_buf->skb = skb;
tx_buf->size = tx_desc->data_size;
- tx_buf->phys = tx_desc->buf_phys_addr;
+ tx_buf->phys = tx_desc->buf_phys_addr + tx_desc->packet_offset;
txq_pcpu->txq_put_index++;
if (txq_pcpu->txq_put_index == txq_pcpu->size)
txq_pcpu->txq_put_index = 0;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index bbff8ec6713e..28a4b34310b2 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -502,8 +502,11 @@ void mlx4_en_recover_from_oom(struct mlx4_en_priv *priv)
return;
for (ring = 0; ring < priv->rx_ring_num; ring++) {
- if (mlx4_en_is_ring_empty(priv->rx_ring[ring]))
+ if (mlx4_en_is_ring_empty(priv->rx_ring[ring])) {
+ local_bh_disable();
napi_reschedule(&priv->rx_cq[ring]->napi);
+ local_bh_enable();
+ }
}
}
diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c
index d52ea3008946..7e8bce46e6b4 100644
--- a/drivers/net/ethernet/ti/cpmac.c
+++ b/drivers/net/ethernet/ti/cpmac.c
@@ -1237,7 +1237,7 @@ int cpmac_init(void)
goto fail_alloc;
}
-#warning FIXME: unhardcode gpio&reset bits
+ /* FIXME: unhardcode gpio&reset bits */
ar7_gpio_disable(26);
ar7_gpio_disable(27);
ar7_device_reset(AR7_RESET_BIT_CPMAC_LO);
diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c
index 860d4aed8274..43617ded3773 100644
--- a/drivers/net/ieee802154/fakelb.c
+++ b/drivers/net/ieee802154/fakelb.c
@@ -30,7 +30,7 @@
static int numlbs = 2;
static LIST_HEAD(fakelb_phys);
-static DEFINE_SPINLOCK(fakelb_phys_lock);
+static DEFINE_MUTEX(fakelb_phys_lock);
static LIST_HEAD(fakelb_ifup_phys);
static DEFINE_RWLOCK(fakelb_ifup_phys_lock);
@@ -180,9 +180,9 @@ static int fakelb_add_one(struct device *dev)
if (err)
goto err_reg;
- spin_lock(&fakelb_phys_lock);
+ mutex_lock(&fakelb_phys_lock);
list_add_tail(&phy->list, &fakelb_phys);
- spin_unlock(&fakelb_phys_lock);
+ mutex_unlock(&fakelb_phys_lock);
return 0;
@@ -214,10 +214,10 @@ static int fakelb_probe(struct platform_device *pdev)
return 0;
err_slave:
- spin_lock(&fakelb_phys_lock);
+ mutex_lock(&fakelb_phys_lock);
list_for_each_entry_safe(phy, tmp, &fakelb_phys, list)
fakelb_del(phy);
- spin_unlock(&fakelb_phys_lock);
+ mutex_unlock(&fakelb_phys_lock);
return err;
}
@@ -225,10 +225,10 @@ static int fakelb_remove(struct platform_device *pdev)
{
struct fakelb_phy *phy, *tmp;
- spin_lock(&fakelb_phys_lock);
+ mutex_lock(&fakelb_phys_lock);
list_for_each_entry_safe(phy, tmp, &fakelb_phys, list)
fakelb_del(phy);
- spin_unlock(&fakelb_phys_lock);
+ mutex_unlock(&fakelb_phys_lock);
return 0;
}
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index dc7d970bd1c0..effcdbfb06e9 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -164,6 +164,7 @@ static void loopback_setup(struct net_device *dev)
{
dev->mtu = 64 * 1024;
dev->hard_header_len = ETH_HLEN; /* 14 */
+ dev->min_header_len = ETH_HLEN; /* 14 */
dev->addr_len = ETH_ALEN; /* 6 */
dev->type = ARPHRD_LOOPBACK; /* 0x0001*/
dev->flags = IFF_LOOPBACK;
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 159a68782bec..79de9608ac48 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -725,7 +725,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
ssize_t n;
if (q->flags & IFF_VNET_HDR) {
- vnet_hdr_len = q->vnet_hdr_sz;
+ vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz);
err = -EINVAL;
if (len < vnet_hdr_len)
@@ -865,7 +865,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
if (q->flags & IFF_VNET_HDR) {
struct virtio_net_hdr vnet_hdr;
- vnet_hdr_len = q->vnet_hdr_sz;
+ vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz);
if (iov_iter_count(iter) < vnet_hdr_len)
return -EINVAL;
diff --git a/drivers/net/rmnet/Kconfig b/drivers/net/rmnet/Kconfig
new file mode 100644
index 000000000000..751893959b57
--- /dev/null
+++ b/drivers/net/rmnet/Kconfig
@@ -0,0 +1,21 @@
+#
+# RMNET MAP driver
+#
+
+menuconfig RMNET
+ depends on NETDEVICES
+ bool "RmNet MAP driver"
+ ---help---
+ If you say Y here, then the rmnet module will be statically
+ compiled into the kernel. The rmnet module provides MAP
+ functionality for embedded and bridged traffic.
+if RMNET
+
+config RMNET_DEBUG
+ bool "RmNet Debug Logging"
+ ---help---
+ Say Y here if you want RmNet to be able to log packets in main
+ system log. This should not be enabled on production builds as it can
+ impact system performance. Note that simply enabling it here will not
+ enable the logging; it must be enabled at run-time as well.
+endif # RMNET
diff --git a/drivers/net/rmnet/Makefile b/drivers/net/rmnet/Makefile
new file mode 100644
index 000000000000..2b6c9cf3756b
--- /dev/null
+++ b/drivers/net/rmnet/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the RMNET module
+#
+
+rmnet-y := rmnet_main.o
+rmnet-y += rmnet_config.o
+rmnet-y += rmnet_vnd.o
+rmnet-y += rmnet_handlers.o
+rmnet-y += rmnet_map_data.o
+rmnet-y += rmnet_map_command.o
+rmnet-y += rmnet_stats.o
+obj-$(CONFIG_RMNET) += rmnet.o
+
+CFLAGS_rmnet_main.o := -I$(src)
diff --git a/drivers/net/rmnet/rmnet_config.c b/drivers/net/rmnet/rmnet_config.c
new file mode 100644
index 000000000000..a20f54adc0b3
--- /dev/null
+++ b/drivers/net/rmnet/rmnet_config.c
@@ -0,0 +1,1157 @@
+/* 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
+ * 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.
+ *
+ * RMNET configuration engine
+ *
+ */
+
+#include <net/sock.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/rmnet.h>
+#include "rmnet_config.h"
+#include "rmnet_handlers.h"
+#include "rmnet_vnd.h"
+#include "rmnet_private.h"
+
+RMNET_LOG_MODULE(RMNET_LOGMASK_CONFIG);
+
+/* Local Definitions and Declarations */
+#define RMNET_LOCAL_LOGICAL_ENDPOINT -1
+#define RMNET_MAX_AGG_COUNT (128)
+
+static struct sock *nl_socket_handle;
+
+static struct netlink_kernel_cfg rmnet_netlink_cfg = {
+ .input = rmnet_config_netlink_msg_handler
+};
+
+static struct notifier_block rmnet_dev_notifier = {
+ .notifier_call = rmnet_config_notify_cb,
+ .next = 0,
+ .priority = 0
+};
+
+struct rmnet_free_vnd_work {
+ struct work_struct work;
+ int vnd_id[RMNET_MAX_VND];
+ int count;
+};
+
+/* Init and Cleanup */
+
+static struct sock *_rmnet_config_start_netlink(void)
+{
+ return netlink_kernel_create(&init_net,
+ RMNET_NETLINK_PROTO,
+ &rmnet_netlink_cfg);
+}
+
+/* rmnet_config_init() - Startup init
+ *
+ * Registers netlink protocol with kernel and opens socket. Netlink handler is
+ * registered with kernel.
+ */
+int rmnet_config_init(void)
+{
+ int rc;
+
+ nl_socket_handle = _rmnet_config_start_netlink();
+ if (!nl_socket_handle) {
+ LOGE("%s", "Failed to init netlink socket");
+ return RMNET_INIT_ERROR;
+ }
+
+ rc = register_netdevice_notifier(&rmnet_dev_notifier);
+ if (rc != 0) {
+ LOGE("Failed to register device notifier; rc=%d", rc);
+ netlink_kernel_release(nl_socket_handle);
+ return RMNET_INIT_ERROR;
+ }
+
+ return 0;
+}
+
+/* rmnet_config_exit() - Cleans up all netlink related resources
+ */
+void rmnet_config_exit(void)
+{
+ int rc;
+
+ netlink_kernel_release(nl_socket_handle);
+ rc = unregister_netdevice_notifier(&rmnet_dev_notifier);
+ if (rc != 0)
+ LOGE("Failed to unregister device notifier; rc=%d", rc);
+}
+
+/* Helper Functions */
+
+/* _rmnet_is_physical_endpoint_associated() - Determines if device is associated
+ * @dev: Device to get check
+ *
+ * Compares device rx_handler callback pointer against known function
+ *
+ * Return:
+ * - 1 if associated
+ * - 0 if NOT associated
+ */
+static inline int _rmnet_is_physical_endpoint_associated(struct net_device *dev)
+{
+ rx_handler_func_t *rx_handler;
+
+ rx_handler = rcu_dereference(dev->rx_handler);
+
+ if (rx_handler == rmnet_rx_handler)
+ return 1;
+ else
+ return 0;
+}
+
+/* _rmnet_get_phys_ep_config() - Get physical ep config for an associated device
+ * @dev: Device to get endpoint configuration from
+ *
+ * Return:
+ * - pointer to configuration if successful
+ * - 0 (null) if device is not associated
+ */
+static inline struct rmnet_phys_ep_conf_s *_rmnet_get_phys_ep_config
+ (struct net_device *dev)
+{
+ if (_rmnet_is_physical_endpoint_associated(dev))
+ return (struct rmnet_phys_ep_conf_s *)
+ rcu_dereference(dev->rx_handler_data);
+ else
+ return NULL;
+}
+
+/* _rmnet_get_logical_ep() - Gets the logical end point configuration
+ * structure for a network device
+ * @dev: Device to get endpoint configuration from
+ * @config_id: Logical endpoint id on device
+ * Retrieves the logical_endpoint_config structure.
+ *
+ * Return:
+ * - End point configuration structure
+ * - NULL in case of an error
+ */
+struct rmnet_logical_ep_conf_s *_rmnet_get_logical_ep(struct net_device *dev,
+ int config_id)
+{
+ struct rmnet_phys_ep_conf_s *config;
+ struct rmnet_logical_ep_conf_s *epconfig_l;
+
+ if (rmnet_vnd_is_vnd(dev)) {
+ epconfig_l = rmnet_vnd_get_le_config(dev);
+ } else {
+ config = _rmnet_get_phys_ep_config(dev);
+
+ if (!config)
+ return NULL;
+
+ if (config_id == RMNET_LOCAL_LOGICAL_ENDPOINT)
+ epconfig_l = &config->local_ep;
+ else
+ epconfig_l = &config->muxed_ep[config_id];
+ }
+
+ return epconfig_l;
+}
+
+static void _rmnet_netlink_set_link_egress_data_format
+ (struct rmnet_nl_msg_s *rmnet_header,
+ struct rmnet_nl_msg_s *resp_rmnet)
+{
+ struct net_device *dev;
+
+ if (!rmnet_header || !resp_rmnet)
+ return;
+
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+ dev = dev_get_by_name(&init_net, rmnet_header->data_format.dev);
+
+ if (!dev) {
+ resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE;
+ return;
+ }
+
+ resp_rmnet->return_code =
+ rmnet_set_egress_data_format(dev,
+ rmnet_header->data_format.flags,
+ rmnet_header->data_format.agg_size,
+ rmnet_header->data_format.agg_count
+ );
+ dev_put(dev);
+}
+
+static void _rmnet_netlink_set_link_ingress_data_format
+ (struct rmnet_nl_msg_s *rmnet_header,
+ struct rmnet_nl_msg_s *resp_rmnet)
+{
+ struct net_device *dev;
+
+ if (!rmnet_header || !resp_rmnet)
+ return;
+
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+
+ dev = dev_get_by_name(&init_net, rmnet_header->data_format.dev);
+ if (!dev) {
+ resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE;
+ return;
+ }
+
+ resp_rmnet->return_code = rmnet_set_ingress_data_format(
+ dev,
+ rmnet_header->data_format.flags);
+ dev_put(dev);
+}
+
+static void _rmnet_netlink_set_logical_ep_config
+ (struct rmnet_nl_msg_s *rmnet_header,
+ struct rmnet_nl_msg_s *resp_rmnet)
+{
+ struct net_device *dev, *dev2;
+
+ if (!rmnet_header || !resp_rmnet)
+ return;
+
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+ if (rmnet_header->local_ep_config.ep_id < -1 ||
+ rmnet_header->local_ep_config.ep_id > 254) {
+ resp_rmnet->return_code = RMNET_CONFIG_BAD_ARGUMENTS;
+ return;
+ }
+
+ dev = dev_get_by_name(&init_net,
+ rmnet_header->local_ep_config.dev);
+
+ dev2 = dev_get_by_name(&init_net,
+ rmnet_header->local_ep_config.next_dev);
+
+ if (dev && dev2)
+ resp_rmnet->return_code =
+ rmnet_set_logical_endpoint_config(
+ dev,
+ rmnet_header->local_ep_config.ep_id,
+ rmnet_header->local_ep_config.operating_mode,
+ dev2);
+ else
+ resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE;
+
+ if (dev)
+ dev_put(dev);
+ if (dev2)
+ dev_put(dev2);
+}
+
+static void _rmnet_netlink_unset_logical_ep_config
+ (struct rmnet_nl_msg_s *rmnet_header,
+ struct rmnet_nl_msg_s *resp_rmnet)
+{
+ struct net_device *dev;
+
+ if (!rmnet_header || !resp_rmnet)
+ return;
+
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+ if (rmnet_header->local_ep_config.ep_id < -1 ||
+ rmnet_header->local_ep_config.ep_id > 254) {
+ resp_rmnet->return_code = RMNET_CONFIG_BAD_ARGUMENTS;
+ return;
+ }
+
+ dev = dev_get_by_name(&init_net, rmnet_header->local_ep_config.dev);
+
+ if (dev) {
+ resp_rmnet->return_code =
+ rmnet_unset_logical_endpoint_config(
+ dev,
+ rmnet_header->local_ep_config.ep_id);
+ dev_put(dev);
+ } else {
+ resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE;
+ }
+}
+
+static void _rmnet_netlink_get_logical_ep_config
+ (struct rmnet_nl_msg_s *rmnet_header,
+ struct rmnet_nl_msg_s *resp_rmnet)
+{
+ struct net_device *dev;
+
+ if (!rmnet_header || !resp_rmnet)
+ return;
+
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+ if (rmnet_header->local_ep_config.ep_id < -1 ||
+ rmnet_header->local_ep_config.ep_id > 254) {
+ resp_rmnet->return_code = RMNET_CONFIG_BAD_ARGUMENTS;
+ return;
+ }
+
+ dev = dev_get_by_name(&init_net, rmnet_header->local_ep_config.dev);
+
+ if (dev) {
+ resp_rmnet->return_code =
+ rmnet_get_logical_endpoint_config(
+ dev,
+ rmnet_header->local_ep_config.ep_id,
+ &resp_rmnet->local_ep_config.operating_mode,
+ resp_rmnet->local_ep_config.next_dev,
+ sizeof(resp_rmnet->local_ep_config.next_dev));
+ } else {
+ resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE;
+ return;
+ }
+
+ if (resp_rmnet->return_code == RMNET_CONFIG_OK) {
+ /* Begin Data */
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNDATA;
+ resp_rmnet->arg_length = sizeof(((struct rmnet_nl_msg_s *)0)
+ ->local_ep_config);
+ }
+ dev_put(dev);
+}
+
+static void _rmnet_netlink_associate_network_device
+ (struct rmnet_nl_msg_s *rmnet_header,
+ struct rmnet_nl_msg_s *resp_rmnet)
+{
+ struct net_device *dev;
+
+ if (!rmnet_header || !resp_rmnet)
+ return;
+
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+
+ dev = dev_get_by_name(&init_net, rmnet_header->data);
+ if (!dev) {
+ resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE;
+ return;
+ }
+
+ resp_rmnet->return_code = rmnet_associate_network_device(dev);
+ dev_put(dev);
+}
+
+static void _rmnet_netlink_unassociate_network_device
+ (struct rmnet_nl_msg_s *rmnet_header,
+ struct rmnet_nl_msg_s *resp_rmnet)
+{
+ struct net_device *dev;
+
+ if (!rmnet_header || !resp_rmnet)
+ return;
+
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+
+ dev = dev_get_by_name(&init_net, rmnet_header->data);
+ if (!dev) {
+ resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE;
+ return;
+ }
+
+ resp_rmnet->return_code = rmnet_unassociate_network_device(dev);
+ dev_put(dev);
+}
+
+static void _rmnet_netlink_get_network_device_associated
+ (struct rmnet_nl_msg_s *rmnet_header,
+ struct rmnet_nl_msg_s *resp_rmnet)
+{
+ struct net_device *dev;
+
+ if (!rmnet_header || !resp_rmnet)
+ return;
+
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+
+ dev = dev_get_by_name(&init_net, rmnet_header->data);
+ if (!dev) {
+ resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE;
+ return;
+ }
+
+ resp_rmnet->return_code = _rmnet_is_physical_endpoint_associated(dev);
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNDATA;
+ dev_put(dev);
+}
+
+static void _rmnet_netlink_get_link_egress_data_format
+ (struct rmnet_nl_msg_s *rmnet_header,
+ struct rmnet_nl_msg_s *resp_rmnet)
+{
+ struct net_device *dev;
+ struct rmnet_phys_ep_conf_s *config;
+
+ if (!rmnet_header || !resp_rmnet)
+ return;
+
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+
+ dev = dev_get_by_name(&init_net, rmnet_header->data_format.dev);
+ if (!dev) {
+ resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE;
+ return;
+ }
+
+ config = _rmnet_get_phys_ep_config(dev);
+ if (!config) {
+ resp_rmnet->return_code = RMNET_CONFIG_INVALID_REQUEST;
+ dev_put(dev);
+ return;
+ }
+
+ /* Begin Data */
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNDATA;
+ resp_rmnet->arg_length = sizeof(((struct rmnet_nl_msg_s *)0)
+ ->data_format);
+ resp_rmnet->data_format.flags = config->egress_data_format;
+ resp_rmnet->data_format.agg_count = 0;
+ resp_rmnet->data_format.agg_size = 0;
+ dev_put(dev);
+}
+
+static void _rmnet_netlink_get_link_ingress_data_format
+ (struct rmnet_nl_msg_s *rmnet_header,
+ struct rmnet_nl_msg_s *resp_rmnet)
+{
+ struct net_device *dev;
+ struct rmnet_phys_ep_conf_s *config;
+
+ if (!rmnet_header || !resp_rmnet)
+ return;
+
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+
+ dev = dev_get_by_name(&init_net, rmnet_header->data_format.dev);
+ if (!dev) {
+ resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE;
+ return;
+ }
+
+ config = _rmnet_get_phys_ep_config(dev);
+ if (!config) {
+ resp_rmnet->return_code = RMNET_CONFIG_INVALID_REQUEST;
+ dev_put(dev);
+ return;
+ }
+
+ /* Begin Data */
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNDATA;
+ resp_rmnet->arg_length = sizeof(((struct rmnet_nl_msg_s *)0)
+ ->data_format);
+ resp_rmnet->data_format.flags = config->ingress_data_format;
+ dev_put(dev);
+}
+
+static void _rmnet_netlink_get_vnd_name
+ (struct rmnet_nl_msg_s *rmnet_header,
+ struct rmnet_nl_msg_s *resp_rmnet)
+{
+ int r;
+
+ if (!rmnet_header || !resp_rmnet)
+ return;
+
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+
+ r = rmnet_vnd_get_name(rmnet_header->vnd.id, resp_rmnet->vnd.vnd_name,
+ RMNET_MAX_STR_LEN);
+
+ if (r != 0) {
+ resp_rmnet->return_code = RMNET_CONFIG_INVALID_REQUEST;
+ return;
+ }
+
+ /* Begin Data */
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNDATA;
+ resp_rmnet->arg_length = sizeof(((struct rmnet_nl_msg_s *)0)->vnd);
+}
+
+/* rmnet_config_netlink_msg_handler() - Netlink message handler callback
+ * @skb: Packet containing netlink messages
+ *
+ * Standard kernel-expected format for a netlink message handler. Processes SKBs
+ * which contain RmNet data specific netlink messages.
+ */
+void rmnet_config_netlink_msg_handler(struct sk_buff *skb)
+{
+ struct nlmsghdr *nlmsg_header, *resp_nlmsg;
+ struct rmnet_nl_msg_s *rmnet_header, *resp_rmnet;
+ int return_pid, response_data_length;
+ struct sk_buff *skb_response;
+
+ response_data_length = 0;
+ nlmsg_header = (struct nlmsghdr *)skb->data;
+ rmnet_header = (struct rmnet_nl_msg_s *)nlmsg_data(nlmsg_header);
+
+ if (!nlmsg_header->nlmsg_pid ||
+ (nlmsg_header->nlmsg_len < sizeof(struct nlmsghdr) +
+ sizeof(struct rmnet_nl_msg_s)))
+ return;
+
+ LOGL("Netlink message pid=%d, seq=%d, length=%d, rmnet_type=%d",
+ nlmsg_header->nlmsg_pid,
+ nlmsg_header->nlmsg_seq,
+ nlmsg_header->nlmsg_len,
+ rmnet_header->message_type);
+
+ return_pid = nlmsg_header->nlmsg_pid;
+
+ skb_response = nlmsg_new(sizeof(struct nlmsghdr)
+ + sizeof(struct rmnet_nl_msg_s),
+ GFP_KERNEL);
+
+ if (!skb_response)
+ return;
+
+ resp_nlmsg = nlmsg_put(skb_response,
+ 0,
+ nlmsg_header->nlmsg_seq,
+ NLMSG_DONE,
+ sizeof(struct rmnet_nl_msg_s),
+ 0);
+
+ resp_rmnet = nlmsg_data(resp_nlmsg);
+
+ if (!resp_rmnet)
+ return;
+
+ resp_rmnet->message_type = rmnet_header->message_type;
+ rtnl_lock();
+ switch (rmnet_header->message_type) {
+ case RMNET_NETLINK_ASSOCIATE_NETWORK_DEVICE:
+ _rmnet_netlink_associate_network_device
+ (rmnet_header, resp_rmnet);
+ break;
+
+ case RMNET_NETLINK_UNASSOCIATE_NETWORK_DEVICE:
+ _rmnet_netlink_unassociate_network_device
+ (rmnet_header, resp_rmnet);
+ break;
+
+ case RMNET_NETLINK_GET_NETWORK_DEVICE_ASSOCIATED:
+ _rmnet_netlink_get_network_device_associated
+ (rmnet_header, resp_rmnet);
+ break;
+
+ case RMNET_NETLINK_SET_LINK_EGRESS_DATA_FORMAT:
+ _rmnet_netlink_set_link_egress_data_format
+ (rmnet_header, resp_rmnet);
+ break;
+
+ case RMNET_NETLINK_GET_LINK_EGRESS_DATA_FORMAT:
+ _rmnet_netlink_get_link_egress_data_format
+ (rmnet_header, resp_rmnet);
+ break;
+
+ case RMNET_NETLINK_SET_LINK_INGRESS_DATA_FORMAT:
+ _rmnet_netlink_set_link_ingress_data_format
+ (rmnet_header, resp_rmnet);
+ break;
+
+ case RMNET_NETLINK_GET_LINK_INGRESS_DATA_FORMAT:
+ _rmnet_netlink_get_link_ingress_data_format
+ (rmnet_header, resp_rmnet);
+ break;
+
+ case RMNET_NETLINK_SET_LOGICAL_EP_CONFIG:
+ _rmnet_netlink_set_logical_ep_config(rmnet_header, resp_rmnet);
+ break;
+
+ case RMNET_NETLINK_UNSET_LOGICAL_EP_CONFIG:
+ _rmnet_netlink_unset_logical_ep_config(rmnet_header,
+ resp_rmnet);
+ break;
+
+ case RMNET_NETLINK_GET_LOGICAL_EP_CONFIG:
+ _rmnet_netlink_get_logical_ep_config(rmnet_header, resp_rmnet);
+ break;
+
+ case RMNET_NETLINK_NEW_VND:
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+ resp_rmnet->return_code =
+ rmnet_create_vnd(rmnet_header->vnd.id);
+ break;
+
+ case RMNET_NETLINK_NEW_VND_WITH_PREFIX:
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+ resp_rmnet->return_code = rmnet_create_vnd_prefix(
+ rmnet_header->vnd.id,
+ rmnet_header->vnd.vnd_name);
+ break;
+
+ case RMNET_NETLINK_FREE_VND:
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+ /* Please check rmnet_vnd_free_dev documentation regarding
+ * the below locking sequence
+ */
+ rtnl_unlock();
+ resp_rmnet->return_code = rmnet_free_vnd(rmnet_header->vnd.id);
+ rtnl_lock();
+ break;
+
+ case RMNET_NETLINK_GET_VND_NAME:
+ _rmnet_netlink_get_vnd_name(rmnet_header, resp_rmnet);
+ break;
+
+ default:
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+ resp_rmnet->return_code = RMNET_CONFIG_UNKNOWN_MESSAGE;
+ break;
+ }
+ rtnl_unlock();
+ nlmsg_unicast(nl_socket_handle, skb_response, return_pid);
+ LOGD("%s", "Done processing command");
+}
+
+/* Configuration API */
+
+/* rmnet_unassociate_network_device() - Unassociate network device
+ * @dev: Device to unassociate
+ *
+ * Frees all structures generate for device. Unregisters rx_handler
+ *
+ * Return:
+ * - RMNET_CONFIG_OK if successful
+ * - RMNET_CONFIG_NO_SUCH_DEVICE dev is null
+ * - RMNET_CONFIG_INVALID_REQUEST if device is not already associated
+ * - RMNET_CONFIG_DEVICE_IN_USE if device has logical ep that wasn't unset
+ * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null
+ */
+int rmnet_unassociate_network_device(struct net_device *dev)
+{
+ struct rmnet_phys_ep_conf_s *config;
+ int config_id = RMNET_LOCAL_LOGICAL_ENDPOINT;
+ struct rmnet_logical_ep_conf_s *epconfig_l;
+
+ ASSERT_RTNL();
+
+ LOGL("(%s);", dev->name);
+
+ if (!dev)
+ return RMNET_CONFIG_NO_SUCH_DEVICE;
+
+ if (!_rmnet_is_physical_endpoint_associated(dev))
+ return RMNET_CONFIG_INVALID_REQUEST;
+
+ for (; config_id < RMNET_MAX_LOGICAL_EP; config_id++) {
+ epconfig_l = _rmnet_get_logical_ep(dev, config_id);
+ if (epconfig_l && epconfig_l->refcount)
+ return RMNET_CONFIG_DEVICE_IN_USE;
+ }
+
+ config = (struct rmnet_phys_ep_conf_s *)
+ rcu_dereference(dev->rx_handler_data);
+
+ if (!config)
+ return RMNET_CONFIG_UNKNOWN_ERROR;
+
+ kfree(config);
+
+ netdev_rx_handler_unregister(dev);
+
+ /* Explicitly release the reference from the device */
+ dev_put(dev);
+ return RMNET_CONFIG_OK;
+}
+
+/* rmnet_set_ingress_data_format() - Set ingress data format on network device
+ * @dev: Device to ingress data format on
+ * @egress_data_format: 32-bit unsigned bitmask of ingress format
+ *
+ * Network device must already have association with RmNet Data driver
+ *
+ * Return:
+ * - RMNET_CONFIG_OK if successful
+ * - RMNET_CONFIG_NO_SUCH_DEVICE dev is null
+ * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null
+ */
+int rmnet_set_ingress_data_format(struct net_device *dev,
+ u32 ingress_data_format)
+{
+ struct rmnet_phys_ep_conf_s *config;
+
+ ASSERT_RTNL();
+
+ LOGL("(%s,0x%08X);", dev->name, ingress_data_format);
+
+ if (!dev)
+ return RMNET_CONFIG_NO_SUCH_DEVICE;
+
+ config = _rmnet_get_phys_ep_config(dev);
+
+ if (!config)
+ return RMNET_CONFIG_INVALID_REQUEST;
+
+ config->ingress_data_format = ingress_data_format;
+
+ return RMNET_CONFIG_OK;
+}
+
+/* rmnet_set_egress_data_format() - Set egress data format on network device
+ * @dev: Device to egress data format on
+ * @egress_data_format: 32-bit unsigned bitmask of egress format
+ *
+ * Network device must already have association with RmNet Data driver
+ *
+ * Return:
+ * - RMNET_CONFIG_OK if successful
+ * - RMNET_CONFIG_NO_SUCH_DEVICE dev is null
+ * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null
+ */
+int rmnet_set_egress_data_format(struct net_device *dev,
+ u32 egress_data_format,
+ u16 agg_size,
+ u16 agg_count)
+{
+ struct rmnet_phys_ep_conf_s *config;
+
+ ASSERT_RTNL();
+
+ LOGL("(%s,0x%08X, %d, %d);",
+ dev->name, egress_data_format, agg_size, agg_count);
+
+ if (!dev)
+ return RMNET_CONFIG_NO_SUCH_DEVICE;
+
+ config = _rmnet_get_phys_ep_config(dev);
+
+ if (!config || (agg_count > RMNET_MAX_AGG_COUNT))
+ return RMNET_CONFIG_UNKNOWN_ERROR;
+
+ config->egress_data_format = egress_data_format;
+
+ return RMNET_CONFIG_OK;
+}
+
+/* rmnet_associate_network_device() - Associate network device
+ * @dev: Device to register with RmNet data
+ *
+ * Typically used on physical network devices. Registers RX handler and private
+ * metadata structures.
+ *
+ * Return:
+ * - RMNET_CONFIG_OK if successful
+ * - RMNET_CONFIG_NO_SUCH_DEVICE dev is null
+ * - RMNET_CONFIG_INVALID_REQUEST if the device to be associated is a vnd
+ * - RMNET_CONFIG_DEVICE_IN_USE if dev rx_handler is already filled
+ * - RMNET_CONFIG_DEVICE_IN_USE if netdev_rx_handler_register() fails
+ */
+int rmnet_associate_network_device(struct net_device *dev)
+{
+ struct rmnet_phys_ep_conf_s *config;
+ int rc;
+
+ ASSERT_RTNL();
+
+ LOGL("(%s);\n", dev->name);
+
+ if (!dev)
+ return RMNET_CONFIG_NO_SUCH_DEVICE;
+
+ if (_rmnet_is_physical_endpoint_associated(dev)) {
+ LOGM("%s is already regestered", dev->name);
+ return RMNET_CONFIG_DEVICE_IN_USE;
+ }
+
+ if (rmnet_vnd_is_vnd(dev)) {
+ LOGM("%s is a vnd", dev->name);
+ return RMNET_CONFIG_INVALID_REQUEST;
+ }
+
+ config = kmalloc(sizeof(*config), GFP_ATOMIC);
+
+ if (!config)
+ return RMNET_CONFIG_NOMEM;
+
+ memset(config, 0, sizeof(struct rmnet_phys_ep_conf_s));
+ config->dev = dev;
+
+ rc = netdev_rx_handler_register(dev, rmnet_rx_handler, config);
+
+ if (rc) {
+ LOGM("netdev_rx_handler_register returns %d", rc);
+ kfree(config);
+ return RMNET_CONFIG_DEVICE_IN_USE;
+ }
+
+ /* Explicitly hold a reference to the device */
+ dev_hold(dev);
+ return RMNET_CONFIG_OK;
+}
+
+/* _rmnet_set_logical_endpoint_config() - Set logical endpoing config on device
+ * @dev: Device to set endpoint configuration on
+ * @config_id: logical endpoint id on device
+ * @epconfig: endpoing configuration structure to set
+ *
+ * Return:
+ * - RMNET_CONFIG_OK if successful
+ * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null
+ * - RMNET_CONFIG_NO_SUCH_DEVICE if device to set config on is null
+ * - RMNET_CONFIG_DEVICE_IN_USE if device already has a logical ep
+ * - RMNET_CONFIG_BAD_ARGUMENTS if logical endpoint id is out of range
+ */
+int _rmnet_set_logical_endpoint_config(struct net_device *dev,
+ int config_id,
+ struct rmnet_logical_ep_conf_s *epconfig)
+{
+ struct rmnet_logical_ep_conf_s *epconfig_l;
+
+ ASSERT_RTNL();
+
+ if (!dev)
+ return RMNET_CONFIG_NO_SUCH_DEVICE;
+
+ if (config_id < RMNET_LOCAL_LOGICAL_ENDPOINT ||
+ config_id >= RMNET_MAX_LOGICAL_EP)
+ return RMNET_CONFIG_BAD_ARGUMENTS;
+
+ epconfig_l = _rmnet_get_logical_ep(dev, config_id);
+
+ if (!epconfig_l)
+ return RMNET_CONFIG_UNKNOWN_ERROR;
+
+ if (epconfig_l->refcount)
+ return RMNET_CONFIG_DEVICE_IN_USE;
+
+ memcpy(epconfig_l, epconfig, sizeof(struct rmnet_logical_ep_conf_s));
+ if (config_id == RMNET_LOCAL_LOGICAL_ENDPOINT)
+ epconfig_l->mux_id = 0;
+ else
+ epconfig_l->mux_id = config_id;
+
+ /* Explicitly hold a reference to the egress device */
+ dev_hold(epconfig_l->egress_dev);
+ return RMNET_CONFIG_OK;
+}
+
+/* _rmnet_unset_logical_endpoint_config() - Un-set the logical endpoing config
+ * on device
+ * @dev: Device to set endpoint configuration on
+ * @config_id: logical endpoint id on device
+ *
+ * Return:
+ * - RMNET_CONFIG_OK if successful
+ * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null
+ * - RMNET_CONFIG_NO_SUCH_DEVICE if device to set config on is null
+ * - RMNET_CONFIG_BAD_ARGUMENTS if logical endpoint id is out of range
+ */
+int _rmnet_unset_logical_endpoint_config(struct net_device *dev,
+ int config_id)
+{
+ struct rmnet_logical_ep_conf_s *epconfig_l = 0;
+
+ ASSERT_RTNL();
+
+ if (!dev)
+ return RMNET_CONFIG_NO_SUCH_DEVICE;
+
+ if (config_id < RMNET_LOCAL_LOGICAL_ENDPOINT ||
+ config_id >= RMNET_MAX_LOGICAL_EP)
+ return RMNET_CONFIG_BAD_ARGUMENTS;
+
+ epconfig_l = _rmnet_get_logical_ep(dev, config_id);
+
+ if (!epconfig_l || !epconfig_l->refcount)
+ return RMNET_CONFIG_NO_SUCH_DEVICE;
+
+ /* Explicitly release the reference from the egress device */
+ dev_put(epconfig_l->egress_dev);
+ memset(epconfig_l, 0, sizeof(struct rmnet_logical_ep_conf_s));
+
+ return RMNET_CONFIG_OK;
+}
+
+/* rmnet_set_logical_endpoint_config() - Set logical endpoint config on a device
+ * @dev: Device to set endpoint configuration on
+ * @config_id: logical endpoint id on device
+ * @rmnet_mode: endpoint mode. Values from: rmnet_config_endpoint_modes_e
+ * @egress_device: device node to forward packet to once done processing in
+ * ingress/egress handlers
+ *
+ * Creates a logical_endpoint_config structure and fills in the information from
+ * function arguments. Calls _rmnet_set_logical_endpoint_config() to finish
+ * configuration. Network device must already have association with RmNet Data
+ * driver
+ *
+ * Return:
+ * - RMNET_CONFIG_OK if successful
+ * - RMNET_CONFIG_BAD_EGRESS_DEVICE if egress device is null
+ * - RMNET_CONFIG_BAD_EGRESS_DEVICE if egress device is not handled by
+ * RmNet data module
+ * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null
+ * - RMNET_CONFIG_NO_SUCH_DEVICE if device to set config on is null
+ * - RMNET_CONFIG_BAD_ARGUMENTS if logical endpoint id is out of range
+ */
+int rmnet_set_logical_endpoint_config(struct net_device *dev,
+ int config_id,
+ u8 rmnet_mode,
+ struct net_device *egress_dev)
+{
+ struct rmnet_logical_ep_conf_s epconfig;
+
+ LOGL("(%s, %d, %d, %s);",
+ dev->name, config_id, rmnet_mode, egress_dev->name);
+
+ if (!egress_dev ||
+ ((!_rmnet_is_physical_endpoint_associated(egress_dev)) &&
+ (!rmnet_vnd_is_vnd(egress_dev)))) {
+ return RMNET_CONFIG_BAD_EGRESS_DEVICE;
+ }
+
+ memset(&epconfig, 0, sizeof(struct rmnet_logical_ep_conf_s));
+ epconfig.refcount = 1;
+ epconfig.rmnet_mode = rmnet_mode;
+ epconfig.egress_dev = egress_dev;
+
+ return _rmnet_set_logical_endpoint_config(dev, config_id, &epconfig);
+}
+
+/* rmnet_unset_logical_endpoint_config() - Un-set logical endpoing configuration
+ * on a device
+ * @dev: Device to set endpoint configuration on
+ * @config_id: logical endpoint id on device
+ *
+ * Retrieves the logical_endpoint_config structure and frees the egress device.
+ * Network device must already have association with RmNet Data driver
+ *
+ * Return:
+ * - RMNET_CONFIG_OK if successful
+ * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null
+ * - RMNET_CONFIG_NO_SUCH_DEVICE device is not associated
+ * - RMNET_CONFIG_BAD_ARGUMENTS if logical endpoint id is out of range
+ */
+int rmnet_unset_logical_endpoint_config(struct net_device *dev,
+ int config_id)
+{
+ LOGL("(%s, %d);", dev->name, config_id);
+
+ if (!dev ||
+ ((!_rmnet_is_physical_endpoint_associated(dev)) &&
+ (!rmnet_vnd_is_vnd(dev)))) {
+ return RMNET_CONFIG_NO_SUCH_DEVICE;
+ }
+
+ return _rmnet_unset_logical_endpoint_config(dev, config_id);
+}
+
+/* rmnet_get_logical_endpoint_config() - Gets logical endpoing configuration
+ * for a device
+ * @dev: Device to get endpoint configuration on
+ * @config_id: logical endpoint id on device
+ * @rmnet_mode: (I/O) logical endpoint mode
+ * @egress_dev_name: (I/O) logical endpoint egress device name
+ * @egress_dev_name_size: The maximal size of the I/O egress_dev_name
+ *
+ * Retrieves the logical_endpoint_config structure.
+ * Network device must already have association with RmNet Data driver
+ *
+ * Return:
+ * - RMNET_CONFIG_OK if successful
+ * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null
+ * - RMNET_CONFIG_NO_SUCH_DEVICE device is not associated
+ * - RMNET_CONFIG_BAD_ARGUMENTS if logical endpoint id is out of range or
+ * if the provided buffer size for egress dev name is too short
+ */
+int rmnet_get_logical_endpoint_config(struct net_device *dev,
+ int config_id,
+ u8 *rmnet_mode,
+ u8 *egress_dev_name,
+ size_t egress_dev_name_size)
+{
+ struct rmnet_logical_ep_conf_s *epconfig_l = 0;
+ size_t strlcpy_res = 0;
+
+ LOGL("(%s, %d);", dev->name, config_id);
+
+ if (!egress_dev_name || !rmnet_mode)
+ return RMNET_CONFIG_BAD_ARGUMENTS;
+ if (config_id < RMNET_LOCAL_LOGICAL_ENDPOINT ||
+ config_id >= RMNET_MAX_LOGICAL_EP)
+ return RMNET_CONFIG_BAD_ARGUMENTS;
+
+ epconfig_l = _rmnet_get_logical_ep(dev, config_id);
+
+ if (!epconfig_l || !epconfig_l->refcount)
+ return RMNET_CONFIG_NO_SUCH_DEVICE;
+
+ *rmnet_mode = epconfig_l->rmnet_mode;
+
+ strlcpy_res = strlcpy(egress_dev_name, epconfig_l->egress_dev->name,
+ egress_dev_name_size);
+
+ if (strlcpy_res >= egress_dev_name_size)
+ return RMNET_CONFIG_BAD_ARGUMENTS;
+
+ return RMNET_CONFIG_OK;
+}
+
+/* rmnet_create_vnd() - Create virtual network device node
+ * @id: RmNet virtual device node id
+ *
+ * Return:
+ * - result of rmnet_vnd_create_dev()
+ */
+int rmnet_create_vnd(int id)
+{
+ struct net_device *dev;
+
+ ASSERT_RTNL();
+ LOGL("(%d);", id);
+ return rmnet_vnd_create_dev(id, &dev, NULL);
+}
+
+/* rmnet_create_vnd() - Create virtual network device node
+ * @id: RmNet virtual device node id
+ * @prefix: String prefix for device name
+ *
+ * Return:
+ * - result of rmnet_vnd_create_dev()
+ */
+int rmnet_create_vnd_prefix(int id, const char *prefix)
+{
+ struct net_device *dev;
+
+ ASSERT_RTNL();
+ LOGL("(%d, \"%s\");", id, prefix);
+ return rmnet_vnd_create_dev(id, &dev, prefix);
+}
+
+/* rmnet_free_vnd() - Free virtual network device node
+ * @id: RmNet virtual device node id
+ *
+ * Return:
+ * - result of rmnet_vnd_free_dev()
+ */
+int rmnet_free_vnd(int id)
+{
+ LOGL("(%d);", id);
+ return rmnet_vnd_free_dev(id);
+}
+
+static void _rmnet_free_vnd_later(struct work_struct *work)
+{
+ int i;
+ struct rmnet_free_vnd_work *fwork;
+
+ fwork = container_of(work, struct rmnet_free_vnd_work, work);
+
+ for (i = 0; i < fwork->count; i++)
+ rmnet_free_vnd(fwork->vnd_id[i]);
+ kfree(fwork);
+}
+
+/* rmnet_force_unassociate_device() - Force a device to unassociate
+ * @dev: Device to unassociate
+ *
+ * Return:
+ * - void
+ */
+static void rmnet_force_unassociate_device(struct net_device *dev)
+{
+ int i, j;
+ struct net_device *vndev;
+ struct rmnet_logical_ep_conf_s *cfg;
+ struct rmnet_free_vnd_work *vnd_work;
+
+ ASSERT_RTNL();
+ if (!dev)
+ return;
+
+ if (!_rmnet_is_physical_endpoint_associated(dev)) {
+ LOGM("%s", "Called on unassociated device, skipping");
+ return;
+ }
+
+ vnd_work = kmalloc(sizeof(*vnd_work), GFP_KERNEL);
+ if (!vnd_work) {
+ LOGH("%s", "Out of Memory");
+ return;
+ }
+ INIT_WORK(&vnd_work->work, _rmnet_free_vnd_later);
+ vnd_work->count = 0;
+
+ /* Check the VNDs for offending mappings */
+ for (i = 0, j = 0; i < RMNET_MAX_VND &&
+ j < RMNET_MAX_VND; i++) {
+ vndev = rmnet_vnd_get_by_id(i);
+ if (!vndev) {
+ LOGL("VND %d not in use; skipping", i);
+ continue;
+ }
+ cfg = rmnet_vnd_get_le_config(vndev);
+ if (!cfg) {
+ LOGH("Got NULL config from VND %d", i);
+ continue;
+ }
+ if (cfg->refcount && (cfg->egress_dev == dev)) {
+ /* Make sure the device is down before clearing any of
+ * the mappings. Otherwise we could see a potential
+ * race condition if packets are actively being
+ * transmitted.
+ */
+ dev_close(vndev);
+ rmnet_unset_logical_endpoint_config
+ (vndev, RMNET_LOCAL_LOGICAL_ENDPOINT);
+ vnd_work->vnd_id[j] = i;
+ j++;
+ }
+ }
+ if (j > 0) {
+ vnd_work->count = j;
+ schedule_work(&vnd_work->work);
+ } else {
+ kfree(vnd_work);
+ }
+
+ /* Clear the mappings on the phys ep */
+ rmnet_unset_logical_endpoint_config(dev, RMNET_LOCAL_LOGICAL_ENDPOINT);
+ for (i = 0; i < RMNET_MAX_LOGICAL_EP; i++)
+ rmnet_unset_logical_endpoint_config(dev, i);
+ rmnet_unassociate_network_device(dev);
+}
+
+/* rmnet_config_notify_cb() - Callback for netdevice notifier chain
+ * @nb: Notifier block data
+ * @event: Netdevice notifier event ID
+ * @data: Contains a net device for which we are getting notified
+ *
+ * Return:
+ * - result of NOTIFY_DONE()
+ */
+int rmnet_config_notify_cb(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(data);
+
+ if (!dev)
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case NETDEV_UNREGISTER_FINAL:
+ case NETDEV_UNREGISTER:
+ LOGH("Kernel is trying to unregister %s", dev->name);
+ rmnet_force_unassociate_device(dev);
+ break;
+
+ default:
+ LOGD("Unhandled event [%lu]", event);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
diff --git a/drivers/net/rmnet/rmnet_config.h b/drivers/net/rmnet/rmnet_config.h
new file mode 100644
index 000000000000..be2fc8964dad
--- /dev/null
+++ b/drivers/net/rmnet/rmnet_config.h
@@ -0,0 +1,107 @@
+/* Copyright (c) 2013-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
+ * 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.
+ *
+ * RMNET Data configuration engine
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/skbuff.h>
+
+#ifndef _RMNET_CONFIG_H_
+#define _RMNET_CONFIG_H_
+
+#define RMNET_MAX_LOGICAL_EP 256
+
+/* struct rmnet_logical_ep_conf_s - Logical end-point configuration
+ *
+ * @refcount: Reference count for this endpoint. 0 signifies the endpoint is not
+ * configured for use
+ * @rmnet_mode: Specifies how the traffic should be finally delivered. Possible
+ * options are available in enum rmnet_config_endpoint_modes_e
+ * @mux_id: Virtual channel ID used by MAP protocol
+ * @egress_dev: Next device to deliver the packet to. Exact usage of this
+ * parmeter depends on the rmnet_mode
+ */
+struct rmnet_logical_ep_conf_s {
+ u8 refcount;
+ u8 rmnet_mode;
+ u8 mux_id;
+ struct timespec flush_time;
+ struct net_device *egress_dev;
+};
+
+/* struct rmnet_phys_ep_conf_s - Physical endpoint configuration
+ * One instance of this structure is instantiated for each net_device associated
+ * with rmnet.
+ *
+ * @dev: The device which is associated with rmnet. Corresponds to this
+ * specific instance of rmnet_phys_ep_conf_s
+ * @local_ep: Default non-muxed endpoint. Used for non-MAP protocols/formats
+ * @muxed_ep: All multiplexed logical endpoints associated with this device
+ * @ingress_data_format: RMNET_INGRESS_FORMAT_* flags from rmnet.h
+ * @egress_data_format: RMNET_EGRESS_FORMAT_* flags from rmnet.h
+ *
+ * @egress_agg_size: Maximum size (bytes) of data which should be aggregated
+ * @egress_agg_count: Maximum count (packets) of data which should be aggregated
+ * Smaller of the two parameters above are chosen for
+ * aggregation
+ * @tail_spacing: Guaranteed padding (bytes) when de-aggregating ingress frames
+ * @agg_time: Wall clock time when aggregated frame was created
+ * @agg_last: Last time the aggregation routing was invoked
+ */
+struct rmnet_phys_ep_conf_s {
+ struct net_device *dev;
+ struct rmnet_logical_ep_conf_s local_ep;
+ struct rmnet_logical_ep_conf_s muxed_ep[RMNET_MAX_LOGICAL_EP];
+ u32 ingress_data_format;
+ u32 egress_data_format;
+};
+
+int rmnet_config_init(void);
+void rmnet_config_exit(void);
+
+int rmnet_unassociate_network_device(struct net_device *dev);
+int rmnet_set_ingress_data_format(struct net_device *dev,
+ u32 ingress_data_format);
+int rmnet_set_egress_data_format(struct net_device *dev,
+ u32 egress_data_format,
+ u16 agg_size,
+ u16 agg_count);
+int rmnet_associate_network_device(struct net_device *dev);
+int _rmnet_set_logical_endpoint_config(struct net_device *dev,
+ int config_id,
+ struct rmnet_logical_ep_conf_s *epconfig);
+int rmnet_set_logical_endpoint_config(struct net_device *dev,
+ int config_id,
+ u8 rmnet_mode,
+ struct net_device *egress_dev);
+int _rmnet_unset_logical_endpoint_config(struct net_device *dev,
+ int config_id);
+int rmnet_unset_logical_endpoint_config(struct net_device *dev,
+ int config_id);
+int _rmnet_get_logical_endpoint_config(struct net_device *dev,
+ int config_id,
+ struct rmnet_logical_ep_conf_s *epconfig);
+int rmnet_get_logical_endpoint_config(struct net_device *dev,
+ int config_id,
+ u8 *rmnet_mode,
+ u8 *egress_dev_name,
+ size_t egress_dev_name_size);
+void rmnet_config_netlink_msg_handler (struct sk_buff *skb);
+int rmnet_config_notify_cb(struct notifier_block *nb,
+ unsigned long event, void *data);
+int rmnet_create_vnd(int id);
+int rmnet_create_vnd_prefix(int id, const char *name);
+int rmnet_free_vnd(int id);
+
+#endif /* _RMNET_CONFIG_H_ */
diff --git a/drivers/net/rmnet/rmnet_handlers.c b/drivers/net/rmnet/rmnet_handlers.c
new file mode 100644
index 000000000000..c2ade2d61e2f
--- /dev/null
+++ b/drivers/net/rmnet/rmnet_handlers.c
@@ -0,0 +1,550 @@
+/* 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
+ * 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.
+ *
+ * RMNET Data ingress/egress handler
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/module.h>
+#include <linux/rmnet.h>
+#include <linux/netdev_features.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include "rmnet_private.h"
+#include "rmnet_config.h"
+#include "rmnet_vnd.h"
+#include "rmnet_map.h"
+#include "rmnet_stats.h"
+#include "rmnet_handlers.h"
+
+RMNET_LOG_MODULE(RMNET_LOGMASK_HANDLER);
+
+#ifdef CONFIG_RMNET_DEBUG
+unsigned int dump_pkt_rx;
+module_param(dump_pkt_rx, uint, 0644);
+MODULE_PARM_DESC(dump_pkt_rx, "Dump packets entering ingress handler");
+
+unsigned int dump_pkt_tx;
+module_param(dump_pkt_tx, uint, 0644);
+MODULE_PARM_DESC(dump_pkt_tx, "Dump packets exiting egress handler");
+#endif /* CONFIG_RMNET_DEBUG */
+
+#define RMNET_IP_VERSION_4 0x40
+#define RMNET_IP_VERSION_6 0x60
+
+/* Helper Functions */
+
+/* __rmnet_set_skb_proto() - Set skb->protocol field
+ * @skb: packet being modified
+ *
+ * Peek at the first byte of the packet and set the protocol. There is not
+ * good way to determine if a packet has a MAP header. As of writing this,
+ * the reserved bit in the MAP frame will prevent it from overlapping with
+ * IPv4/IPv6 frames. This could change in the future!
+ */
+static inline void __rmnet_set_skb_proto(struct sk_buff *skb)
+{
+ switch (skb->data[0] & 0xF0) {
+ case RMNET_IP_VERSION_4:
+ skb->protocol = htons(ETH_P_IP);
+ break;
+ case RMNET_IP_VERSION_6:
+ skb->protocol = htons(ETH_P_IPV6);
+ break;
+ default:
+ skb->protocol = htons(ETH_P_MAP);
+ break;
+ }
+}
+
+#ifdef CONFIG_RMNET_DEBUG
+/* rmnet_print_packet() - Print packet / diagnostics
+ * @skb: Packet to print
+ * @printlen: Number of bytes to print
+ * @dev: Name of interface
+ * @dir: Character representing direction (e.g.. 'r' for receive)
+ *
+ * This function prints out raw bytes in an SKB. Use of this will have major
+ * performance impacts and may even trigger watchdog resets if too much is being
+ * printed. Hence, this should always be compiled out unless absolutely needed.
+ */
+void rmnet_print_packet(const struct sk_buff *skb, const char *dev, char dir)
+{
+ char buffer[200];
+ unsigned int len, printlen;
+ int i, buffloc = 0;
+
+ switch (dir) {
+ case 'r':
+ printlen = dump_pkt_rx;
+ break;
+
+ case 't':
+ printlen = dump_pkt_tx;
+ break;
+
+ default:
+ printlen = 0;
+ break;
+ }
+
+ if (!printlen)
+ return;
+
+ pr_err("[%s][%c] - PKT skb->len=%d skb->head=%pK skb->data=%pK\n",
+ dev, dir, skb->len, (void *)skb->head, (void *)skb->data);
+ pr_err("[%s][%c] - PKT skb->tail=%pK skb->end=%pK\n",
+ dev, dir, skb_tail_pointer(skb), skb_end_pointer(skb));
+
+ if (skb->len > 0)
+ len = skb->len;
+ else
+ len = ((unsigned int)(uintptr_t)skb->end) -
+ ((unsigned int)(uintptr_t)skb->data);
+
+ pr_err("[%s][%c] - PKT len: %d, printing first %d bytes\n",
+ dev, dir, len, printlen);
+
+ memset(buffer, 0, sizeof(buffer));
+ for (i = 0; (i < printlen) && (i < len); i++) {
+ if ((i % 16) == 0) {
+ pr_err("[%s][%c] - PKT%s\n", dev, dir, buffer);
+ memset(buffer, 0, sizeof(buffer));
+ buffloc = 0;
+ buffloc += snprintf(&buffer[buffloc],
+ sizeof(buffer) - buffloc, "%04X:",
+ i);
+ }
+
+ buffloc += snprintf(&buffer[buffloc], sizeof(buffer) - buffloc,
+ " %02x", skb->data[i]);
+ }
+ pr_err("[%s][%c] - PKT%s\n", dev, dir, buffer);
+}
+#else
+void rmnet_print_packet(const struct sk_buff *skb, const char *dev, char dir)
+{
+}
+#endif /* CONFIG_RMNET_DEBUG */
+
+/* Generic handler */
+
+/* rmnet_bridge_handler() - Bridge related functionality
+ *
+ * Return:
+ * - RX_HANDLER_CONSUMED in all cases
+ */
+static rx_handler_result_t rmnet_bridge_handler
+ (struct sk_buff *skb, struct rmnet_logical_ep_conf_s *ep)
+{
+ if (!ep->egress_dev) {
+ LOGD("Missing egress device for packet arriving on %s",
+ skb->dev->name);
+ rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_BRDG_NO_EGRESS);
+ } else {
+ rmnet_egress_handler(skb, ep);
+ }
+
+ return RX_HANDLER_CONSUMED;
+}
+
+#ifdef NET_SKBUFF_DATA_USES_OFFSET
+static void rmnet_reset_mac_header(struct sk_buff *skb)
+{
+ skb->mac_header = 0;
+ skb->mac_len = 0;
+}
+#else
+static void rmnet_reset_mac_header(struct sk_buff *skb)
+{
+ skb->mac_header = skb->network_header;
+ skb->mac_len = 0;
+}
+#endif /*NET_SKBUFF_DATA_USES_OFFSET*/
+
+/* __rmnet_deliver_skb() - Deliver skb
+ *
+ * Determines where to deliver skb. Options are: consume by network stack,
+ * pass to bridge handler, or pass to virtual network device
+ *
+ * Return:
+ * - RX_HANDLER_CONSUMED if packet forwarded or dropped
+ * - RX_HANDLER_PASS if packet is to be consumed by network stack as-is
+ */
+static rx_handler_result_t __rmnet_deliver_skb
+ (struct sk_buff *skb, struct rmnet_logical_ep_conf_s *ep)
+{
+ switch (ep->rmnet_mode) {
+ case RMNET_EPMODE_NONE:
+ return RX_HANDLER_PASS;
+
+ case RMNET_EPMODE_BRIDGE:
+ return rmnet_bridge_handler(skb, ep);
+
+ case RMNET_EPMODE_VND:
+ skb_reset_transport_header(skb);
+ skb_reset_network_header(skb);
+ switch (rmnet_vnd_rx_fixup(skb, skb->dev)) {
+ case RX_HANDLER_CONSUMED:
+ return RX_HANDLER_CONSUMED;
+
+ case RX_HANDLER_PASS:
+ skb->pkt_type = PACKET_HOST;
+ rmnet_reset_mac_header(skb);
+ netif_receive_skb(skb);
+ return RX_HANDLER_CONSUMED;
+ }
+ return RX_HANDLER_PASS;
+
+ default:
+ LOGD("Unknown ep mode %d", ep->rmnet_mode);
+ rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_DELIVER_NO_EP);
+ return RX_HANDLER_CONSUMED;
+ }
+}
+
+/* rmnet_ingress_deliver_packet() - Ingress handler for raw IP and bridged
+ * MAP packets.
+ * @skb: Packet needing a destination.
+ * @config: Physical end point configuration that the packet arrived on.
+ *
+ * Return:
+ * - RX_HANDLER_CONSUMED if packet forwarded/dropped
+ * - RX_HANDLER_PASS if packet should be passed up the stack by caller
+ */
+static rx_handler_result_t rmnet_ingress_deliver_packet
+ (struct sk_buff *skb, struct rmnet_phys_ep_conf_s *config)
+{
+ if (!config) {
+ LOGD("%s", "NULL physical EP provided");
+ kfree_skb(skb);
+ return RX_HANDLER_CONSUMED;
+ }
+
+ if (!(config->local_ep.refcount)) {
+ LOGD("Packet on %s has no local endpoint configuration",
+ skb->dev->name);
+ rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_IPINGRESS_NO_EP);
+ return RX_HANDLER_CONSUMED;
+ }
+
+ skb->dev = config->local_ep.egress_dev;
+
+ return __rmnet_deliver_skb(skb, &config->local_ep);
+}
+
+/* MAP handler */
+
+/* _rmnet_map_ingress_handler() - Actual MAP ingress handler
+ * @skb: Packet being received
+ * @config: Physical endpoint configuration for the ingress device
+ *
+ * Most MAP ingress functions are processed here. Packets are processed
+ * individually; aggregated packets should use rmnet_map_ingress_handler()
+ *
+ * Return:
+ * - RX_HANDLER_CONSUMED if packet is dropped
+ * - result of __rmnet_deliver_skb() for all other cases
+ */
+static rx_handler_result_t _rmnet_map_ingress_handler
+ (struct sk_buff *skb, struct rmnet_phys_ep_conf_s *config)
+{
+ struct rmnet_logical_ep_conf_s *ep;
+ u8 mux_id;
+ u16 len;
+
+ if (RMNET_MAP_GET_CD_BIT(skb)) {
+ if (config->ingress_data_format
+ & RMNET_INGRESS_FORMAT_MAP_COMMANDS)
+ return rmnet_map_command(skb, config);
+
+ LOGM("MAP command packet on %s; %s", skb->dev->name,
+ "Not configured for MAP commands");
+ rmnet_kfree_skb(skb,
+ RMNET_STATS_SKBFREE_INGRESS_NOT_EXPECT_MAPC);
+ return RX_HANDLER_CONSUMED;
+ }
+
+ mux_id = RMNET_MAP_GET_MUX_ID(skb);
+ len = RMNET_MAP_GET_LENGTH(skb) - RMNET_MAP_GET_PAD(skb);
+
+ if (mux_id >= RMNET_MAX_LOGICAL_EP) {
+ LOGD("Got packet on %s with bad mux id %d",
+ skb->dev->name, mux_id);
+ rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPINGRESS_BAD_MUX);
+ return RX_HANDLER_CONSUMED;
+ }
+
+ ep = &config->muxed_ep[mux_id];
+
+ if (!ep->refcount) {
+ LOGD("Packet on %s:%d; has no logical endpoint config",
+ skb->dev->name, mux_id);
+
+ rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPINGRESS_MUX_NO_EP);
+ return RX_HANDLER_CONSUMED;
+ }
+
+ if (config->ingress_data_format & RMNET_INGRESS_FORMAT_DEMUXING)
+ skb->dev = ep->egress_dev;
+
+ /* Subtract MAP header */
+ skb_pull(skb, sizeof(struct rmnet_map_header_s));
+ skb_trim(skb, len);
+ __rmnet_set_skb_proto(skb);
+ return __rmnet_deliver_skb(skb, ep);
+}
+
+/* rmnet_map_ingress_handler() - MAP ingress handler
+ * @skb: Packet being received
+ * @config: Physical endpoint configuration for the ingress device
+ *
+ * Called if and only if MAP is configured in the ingress device's ingress data
+ * format. Deaggregation is done here, actual MAP processing is done in
+ * _rmnet_map_ingress_handler().
+ *
+ * Return:
+ * - RX_HANDLER_CONSUMED for aggregated packets
+ * - RX_HANDLER_CONSUMED for dropped packets
+ * - result of _rmnet_map_ingress_handler() for all other cases
+ */
+static rx_handler_result_t rmnet_map_ingress_handler
+ (struct sk_buff *skb, struct rmnet_phys_ep_conf_s *config)
+{
+ struct sk_buff *skbn;
+ int rc, co = 0;
+
+ if (config->ingress_data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) {
+ while ((skbn = rmnet_map_deaggregate(skb, config)) != NULL) {
+ _rmnet_map_ingress_handler(skbn, config);
+ co++;
+ }
+ LOGD("De-aggregated %d packets", co);
+ rmnet_stats_deagg_pkts(co);
+ rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPINGRESS_AGGBUF);
+ rc = RX_HANDLER_CONSUMED;
+ } else {
+ rc = _rmnet_map_ingress_handler(skb, config);
+ }
+
+ return rc;
+}
+
+/* rmnet_map_egress_handler() - MAP egress handler
+ * @skb: Packet being sent
+ * @config: Physical endpoint configuration for the egress device
+ * @ep: logical endpoint configuration of the packet originator
+ * (e.g.. RmNet virtual network device)
+ * @orig_dev: The originator vnd device
+ *
+ * Called if and only if MAP is configured in the egress device's egress data
+ * format. Will expand skb if there is insufficient headroom for MAP protocol.
+ * Note: headroomexpansion will incur a performance penalty.
+ *
+ * Return:
+ * - 0 on success
+ * - 1 on failure
+ */
+static int rmnet_map_egress_handler(struct sk_buff *skb,
+ struct rmnet_phys_ep_conf_s *config,
+ struct rmnet_logical_ep_conf_s *ep,
+ struct net_device *orig_dev)
+{
+ int required_headroom, additional_header_length;
+ struct rmnet_map_header_s *map_header;
+
+ additional_header_length = 0;
+ required_headroom = sizeof(struct rmnet_map_header_s);
+
+ LOGD("headroom of %d bytes", required_headroom);
+
+ if (skb_headroom(skb) < required_headroom) {
+ if (pskb_expand_head(skb, required_headroom, 0, GFP_KERNEL)) {
+ LOGD("Failed to add headroom of %d bytes",
+ required_headroom);
+ return RMNET_MAP_CONSUMED;
+ }
+ }
+
+ map_header = rmnet_map_add_map_header
+ (skb, additional_header_length, RMNET_MAP_NO_PAD_BYTES);
+
+ if (!map_header) {
+ LOGD("%s", "Failed to add MAP header to egress packet");
+ return RMNET_MAP_CONSUMED;
+ }
+
+ if (config->egress_data_format & RMNET_EGRESS_FORMAT_MUXING) {
+ if (ep->mux_id == 0xff)
+ map_header->mux_id = 0;
+ else
+ map_header->mux_id = ep->mux_id;
+ }
+
+ skb->protocol = htons(ETH_P_MAP);
+
+ return RMNET_MAP_SUCCESS;
+}
+
+/* Ingress / Egress Entry Points */
+
+/* rmnet_ingress_handler() - Ingress handler entry point
+ * @skb: Packet being received
+ *
+ * Processes packet as per ingress data format for receiving device. Logical
+ * endpoint is determined from packet inspection. Packet is then sent to the
+ * egress device listed in the logical endpoint configuration.
+ *
+ * Return:
+ * - RX_HANDLER_PASS if packet is not processed by handler (caller must
+ * deal with the packet)
+ * - RX_HANDLER_CONSUMED if packet is forwarded or processed by MAP
+ */
+rx_handler_result_t rmnet_ingress_handler(struct sk_buff *skb)
+{
+ struct rmnet_phys_ep_conf_s *config;
+ struct net_device *dev;
+ int rc;
+
+ if (!skb)
+ return RX_HANDLER_CONSUMED;
+
+ dev = skb->dev;
+ rmnet_print_packet(skb, dev->name, 'r');
+
+ config = (struct rmnet_phys_ep_conf_s *)
+ rcu_dereference(skb->dev->rx_handler_data);
+
+ if (!config) {
+ LOGD("%s is not associated with rmnet", skb->dev->name);
+ kfree_skb(skb);
+ return RX_HANDLER_CONSUMED;
+ }
+
+ /* Sometimes devices operate in ethernet mode even thouth there is no
+ * ethernet header. This causes the skb->protocol to contain a bogus
+ * value and the skb->data pointer to be off by 14 bytes. Fix it if
+ * configured to do so
+ */
+ if (config->ingress_data_format & RMNET_INGRESS_FIX_ETHERNET) {
+ skb_push(skb, RMNET_ETHERNET_HEADER_LENGTH);
+ __rmnet_set_skb_proto(skb);
+ }
+
+ if (config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP) {
+ rc = rmnet_map_ingress_handler(skb, config);
+ } else {
+ switch (ntohs(skb->protocol)) {
+ case ETH_P_MAP:
+ if (config->local_ep.rmnet_mode ==
+ RMNET_EPMODE_BRIDGE) {
+ rc = rmnet_ingress_deliver_packet(skb, config);
+ } else {
+ LOGD("MAP packet on %s; MAP not set",
+ dev->name);
+ rmnet_kfree_skb
+ (skb,
+ RMNET_STATS_SKBFREE_INGRESS_NOT_EXPECT_MAPD);
+ rc = RX_HANDLER_CONSUMED;
+ }
+ break;
+
+ case ETH_P_ARP:
+ case ETH_P_IP:
+ case ETH_P_IPV6:
+ rc = rmnet_ingress_deliver_packet(skb, config);
+ break;
+
+ default:
+ LOGD("Unknown skb->proto 0x%04X",
+ ntohs(skb->protocol) & 0xFFFF);
+ rc = RX_HANDLER_PASS;
+ }
+ }
+
+ return rc;
+}
+
+/* rmnet_rx_handler() - Rx handler callback registered with kernel
+ * @pskb: Packet to be processed by rx handler
+ *
+ * Standard kernel-expected footprint for rx handlers. Calls
+ * rmnet_ingress_handler with correctly formatted arguments
+ *
+ * Return:
+ * - Whatever rmnet_ingress_handler() returns
+ */
+rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
+{
+ return rmnet_ingress_handler(*pskb);
+}
+
+/* rmnet_egress_handler() - Egress handler entry point
+ * @skb: packet to transmit
+ * @ep: logical endpoint configuration of the packet originator
+ * (e.g.. RmNet virtual network device)
+ *
+ * Modifies packet as per logical endpoint configuration and egress data format
+ * for egress device configured in logical endpoint. Packet is then transmitted
+ * on the egress device.
+ */
+void rmnet_egress_handler(struct sk_buff *skb,
+ struct rmnet_logical_ep_conf_s *ep)
+{
+ struct rmnet_phys_ep_conf_s *config;
+ struct net_device *orig_dev;
+ int rc;
+
+ orig_dev = skb->dev;
+ skb->dev = ep->egress_dev;
+
+ config = (struct rmnet_phys_ep_conf_s *)
+ rcu_dereference(skb->dev->rx_handler_data);
+
+ if (!config) {
+ LOGD("%s is not associated with rmnet", skb->dev->name);
+ kfree_skb(skb);
+ return;
+ }
+
+ LOGD("Packet going out on %s with egress format 0x%08X",
+ skb->dev->name, config->egress_data_format);
+
+ if (config->egress_data_format & RMNET_EGRESS_FORMAT_MAP) {
+ switch (rmnet_map_egress_handler(skb, config, ep, orig_dev)) {
+ case RMNET_MAP_CONSUMED:
+ LOGD("%s", "MAP process consumed packet");
+ return;
+
+ case RMNET_MAP_SUCCESS:
+ break;
+
+ default:
+ LOGD("MAP egress failed on packet on %s",
+ skb->dev->name);
+ rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_EGR_MAPFAIL);
+ return;
+ }
+ }
+
+ if (ep->rmnet_mode == RMNET_EPMODE_VND)
+ rmnet_vnd_tx_fixup(skb, orig_dev);
+
+ rmnet_print_packet(skb, skb->dev->name, 't');
+ rc = dev_queue_xmit(skb);
+ if (rc != 0) {
+ LOGD("Failed to queue packet for transmission on [%s]",
+ skb->dev->name);
+ }
+ rmnet_stats_queue_xmit(rc, RMNET_STATS_QUEUE_XMIT_EGRESS);
+}
diff --git a/drivers/net/rmnet/rmnet_handlers.h b/drivers/net/rmnet/rmnet_handlers.h
new file mode 100644
index 000000000000..43c42c2130cd
--- /dev/null
+++ b/drivers/net/rmnet/rmnet_handlers.h
@@ -0,0 +1,24 @@
+/* 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
+ * 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.
+ *
+ * RMNET Data ingress/egress handler
+ *
+ */
+
+#ifndef _RMNET_HANDLERS_H_
+#define _RMNET_HANDLERS_H_
+
+void rmnet_egress_handler(struct sk_buff *skb,
+ struct rmnet_logical_ep_conf_s *ep);
+
+rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb);
+
+#endif /* _RMNET_HANDLERS_H_ */
diff --git a/drivers/net/rmnet/rmnet_main.c b/drivers/net/rmnet/rmnet_main.c
new file mode 100644
index 000000000000..677791893ad4
--- /dev/null
+++ b/drivers/net/rmnet/rmnet_main.c
@@ -0,0 +1,60 @@
+/* Copyright (c) 2013-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
+ * 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.
+ *
+ *
+ * RMNET Data generic framework
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include "rmnet_private.h"
+#include "rmnet_config.h"
+#include "rmnet_vnd.h"
+
+/* Trace Points */
+#define CREATE_TRACE_POINTS
+#include "rmnet_trace.h"
+
+/* Module Parameters */
+unsigned int rmnet_log_level = RMNET_LOG_LVL_ERR | RMNET_LOG_LVL_HI;
+module_param(rmnet_log_level, uint, 0644);
+MODULE_PARM_DESC(log_level, "Logging level");
+
+unsigned int rmnet_log_module_mask;
+module_param(rmnet_log_module_mask, uint, 0644);
+MODULE_PARM_DESC(rmnet_log_module_mask, "Logging module mask");
+
+/* Startup/Shutdown */
+
+/* rmnet_init() - Module initialization
+ *
+ * todo: check for (and init) startup errors
+ */
+static int __init rmnet_init(void)
+{
+ rmnet_config_init();
+ rmnet_vnd_init();
+
+ LOGL("%s", "RMNET Data driver loaded successfully");
+ return 0;
+}
+
+static void __exit rmnet_exit(void)
+{
+ rmnet_config_exit();
+ rmnet_vnd_exit();
+}
+
+module_init(rmnet_init)
+module_exit(rmnet_exit)
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/rmnet/rmnet_map.h b/drivers/net/rmnet/rmnet_map.h
new file mode 100644
index 000000000000..7d533aa5fbca
--- /dev/null
+++ b/drivers/net/rmnet/rmnet_map.h
@@ -0,0 +1,100 @@
+/* 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
+ * 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/types.h>
+#include <linux/spinlock.h>
+
+#ifndef _RMNET_MAP_H_
+#define _RMNET_MAP_H_
+
+struct rmnet_map_control_command_s {
+ u8 command_name;
+ u8 cmd_type:2;
+ u8 reserved:6;
+ u16 reserved2;
+ u32 transaction_id;
+ union {
+ u8 data[65528];
+ struct {
+ u16 ip_family:2;
+ u16 reserved:14;
+ u16 flow_control_seq_num;
+ u32 qos_id;
+ } flow_control;
+ };
+} __aligned(1);
+
+enum rmnet_map_results_e {
+ RMNET_MAP_SUCCESS,
+ RMNET_MAP_CONSUMED,
+ RMNET_MAP_GENERAL_FAILURE,
+ RMNET_MAP_NOT_ENABLED,
+ RMNET_MAP_FAILED_AGGREGATION,
+ RMNET_MAP_FAILED_MUX
+};
+
+enum rmnet_map_mux_errors_e {
+ RMNET_MAP_MUX_SUCCESS,
+ RMNET_MAP_MUX_INVALID_MUX_ID,
+ RMNET_MAP_MUX_INVALID_PAD_LENGTH,
+ RMNET_MAP_MUX_INVALID_PKT_LENGTH,
+ /* This should always be the last element */
+ RMNET_MAP_MUX_ENUM_LENGTH
+};
+
+enum rmnet_map_commands_e {
+ RMNET_MAP_COMMAND_NONE,
+ RMNET_MAP_COMMAND_FLOW_DISABLE,
+ RMNET_MAP_COMMAND_FLOW_ENABLE,
+ /* These should always be the last 2 elements */
+ RMNET_MAP_COMMAND_UNKNOWN,
+ RMNET_MAP_COMMAND_ENUM_LENGTH
+};
+
+struct rmnet_map_header_s {
+ u8 pad_len:6;
+ u8 reserved_bit:1;
+ u8 cd_bit:1;
+ u8 mux_id;
+ u16 pkt_len;
+} __aligned(1);
+
+#define RMNET_MAP_GET_MUX_ID(Y) (((struct rmnet_map_header_s *) \
+ (Y)->data)->mux_id)
+#define RMNET_MAP_GET_CD_BIT(Y) (((struct rmnet_map_header_s *) \
+ (Y)->data)->cd_bit)
+#define RMNET_MAP_GET_PAD(Y) (((struct rmnet_map_header_s *) \
+ (Y)->data)->pad_len)
+#define RMNET_MAP_GET_CMD_START(Y) ((struct rmnet_map_control_command_s *) \
+ ((Y)->data + \
+ sizeof(struct rmnet_map_header_s)))
+#define RMNET_MAP_GET_LENGTH(Y) (ntohs(((struct rmnet_map_header_s *) \
+ (Y)->data)->pkt_len))
+
+#define RMNET_MAP_COMMAND_REQUEST 0
+#define RMNET_MAP_COMMAND_ACK 1
+#define RMNET_MAP_COMMAND_UNSUPPORTED 2
+#define RMNET_MAP_COMMAND_INVALID 3
+
+#define RMNET_MAP_NO_PAD_BYTES 0
+#define RMNET_MAP_ADD_PAD_BYTES 1
+
+u8 rmnet_map_demultiplex(struct sk_buff *skb);
+struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,
+ struct rmnet_phys_ep_conf_s *config);
+
+struct rmnet_map_header_s *rmnet_map_add_map_header(struct sk_buff *skb,
+ int hdrlen, int pad);
+rx_handler_result_t rmnet_map_command(struct sk_buff *skb,
+ struct rmnet_phys_ep_conf_s *config);
+
+#endif /* _RMNET_MAP_H_ */
diff --git a/drivers/net/rmnet/rmnet_map_command.c b/drivers/net/rmnet/rmnet_map_command.c
new file mode 100644
index 000000000000..13bcee3cfdac
--- /dev/null
+++ b/drivers/net/rmnet/rmnet_map_command.c
@@ -0,0 +1,180 @@
+/* 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
+ * 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/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/rmnet.h>
+#include <net/pkt_sched.h>
+#include "rmnet_config.h"
+#include "rmnet_map.h"
+#include "rmnet_private.h"
+#include "rmnet_vnd.h"
+#include "rmnet_stats.h"
+
+RMNET_LOG_MODULE(RMNET_LOGMASK_MAPC);
+
+unsigned long int rmnet_map_command_stats[RMNET_MAP_COMMAND_ENUM_LENGTH];
+module_param_array(rmnet_map_command_stats, ulong, 0, 0444);
+MODULE_PARM_DESC(rmnet_map_command_stats, "MAP command statistics");
+
+/* rmnet_map_do_flow_control() - Process MAP flow control command
+ * @skb: Socket buffer containing the MAP flow control message
+ * @config: Physical end-point configuration of ingress device
+ * @enable: boolean for enable/disable
+ *
+ * Process in-band MAP flow control messages. Assumes mux ID is mapped to a
+ * RmNet Data vitrual network device.
+ *
+ * Return:
+ * - RMNET_MAP_COMMAND_UNSUPPORTED on any error
+ * - RMNET_MAP_COMMAND_ACK on success
+ */
+static u8 rmnet_map_do_flow_control(struct sk_buff *skb,
+ struct rmnet_phys_ep_conf_s *config,
+ int enable)
+{
+ struct rmnet_map_control_command_s *cmd;
+ struct net_device *vnd;
+ struct rmnet_logical_ep_conf_s *ep;
+ u8 mux_id;
+ u16 ip_family;
+ u16 fc_seq;
+ u32 qos_id;
+ int r;
+
+ if (unlikely(!skb || !config))
+ return RX_HANDLER_CONSUMED;
+
+ mux_id = RMNET_MAP_GET_MUX_ID(skb);
+ cmd = RMNET_MAP_GET_CMD_START(skb);
+
+ if (mux_id >= RMNET_MAX_LOGICAL_EP) {
+ LOGD("Got packet on %s with bad mux id %d",
+ skb->dev->name, mux_id);
+ rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPC_BAD_MUX);
+ return RX_HANDLER_CONSUMED;
+ }
+
+ ep = &config->muxed_ep[mux_id];
+
+ if (!ep->refcount) {
+ LOGD("Packet on %s:%d; has no logical endpoint config",
+ skb->dev->name, mux_id);
+
+ rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPC_MUX_NO_EP);
+ return RX_HANDLER_CONSUMED;
+ }
+
+ vnd = ep->egress_dev;
+
+ ip_family = cmd->flow_control.ip_family;
+ fc_seq = ntohs(cmd->flow_control.flow_control_seq_num);
+ qos_id = ntohl(cmd->flow_control.qos_id);
+
+ /* Ignore the ip family and pass the sequence number for both v4 and v6
+ * sequence. User space does not support creating dedicated flows for
+ * the 2 protocols
+ */
+ r = rmnet_vnd_do_flow_control(vnd, enable);
+ LOGD("dev:%s, qos_id:0x%08X, ip_family:%hd, fc_seq %hd, en:%d",
+ skb->dev->name, qos_id, ip_family & 3, fc_seq, enable);
+
+ if (r) {
+ rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPC_UNSUPPORTED);
+ return RMNET_MAP_COMMAND_UNSUPPORTED;
+ } else {
+ return RMNET_MAP_COMMAND_ACK;
+ }
+}
+
+/* rmnet_map_send_ack() - Send N/ACK message for MAP commands
+ * @skb: Socket buffer containing the MAP command message
+ * @type: N/ACK message selector
+ * @config: Physical end-point configuration of ingress device
+ *
+ * skb is modified to contain the message type selector. The message is then
+ * transmitted on skb->dev. Note that this function grabs global Tx lock on
+ * skb->dev for latency reasons.
+ *
+ * Return:
+ * - void
+ */
+static void rmnet_map_send_ack(struct sk_buff *skb,
+ unsigned char type,
+ struct rmnet_phys_ep_conf_s *config)
+{
+ struct rmnet_map_control_command_s *cmd;
+ int xmit_status;
+
+ if (unlikely(!skb))
+ return;
+
+ skb->protocol = htons(ETH_P_MAP);
+
+ cmd = RMNET_MAP_GET_CMD_START(skb);
+ cmd->cmd_type = type & 0x03;
+
+ netif_tx_lock(skb->dev);
+ xmit_status = skb->dev->netdev_ops->ndo_start_xmit(skb, skb->dev);
+ netif_tx_unlock(skb->dev);
+
+ LOGD("MAP command ACK=%hhu sent with rc: %d", type & 0x03, xmit_status);
+}
+
+/* rmnet_map_command() - Entry point for handling MAP commands
+ * @skb: Socket buffer containing the MAP command message
+ * @config: Physical end-point configuration of ingress device
+ *
+ * Process MAP command frame and send N/ACK message as appropriate. Message cmd
+ * name is decoded here and appropriate handler is called.
+ *
+ * Return:
+ * - RX_HANDLER_CONSUMED. Command frames are always consumed.
+ */
+rx_handler_result_t rmnet_map_command(struct sk_buff *skb,
+ struct rmnet_phys_ep_conf_s *config)
+{
+ struct rmnet_map_control_command_s *cmd;
+ unsigned char command_name;
+ unsigned char rc = 0;
+
+ if (unlikely(!skb))
+ return RX_HANDLER_CONSUMED;
+
+ cmd = RMNET_MAP_GET_CMD_START(skb);
+ command_name = cmd->command_name;
+
+ if (command_name < RMNET_MAP_COMMAND_ENUM_LENGTH)
+ rmnet_map_command_stats[command_name]++;
+
+ switch (command_name) {
+ case RMNET_MAP_COMMAND_FLOW_ENABLE:
+ rc = rmnet_map_do_flow_control(skb, config, 1);
+ break;
+
+ case RMNET_MAP_COMMAND_FLOW_DISABLE:
+ rc = rmnet_map_do_flow_control(skb, config, 0);
+ break;
+
+ default:
+ rmnet_map_command_stats[RMNET_MAP_COMMAND_UNKNOWN]++;
+ LOGM("Uknown MAP command: %d", command_name);
+ rc = RMNET_MAP_COMMAND_UNSUPPORTED;
+ rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPC_UNSUPPORTED);
+ break;
+ }
+ if (rc == RMNET_MAP_COMMAND_ACK)
+ rmnet_map_send_ack(skb, rc, config);
+ return RX_HANDLER_CONSUMED;
+}
diff --git a/drivers/net/rmnet/rmnet_map_data.c b/drivers/net/rmnet/rmnet_map_data.c
new file mode 100644
index 000000000000..1b4eda9f46a5
--- /dev/null
+++ b/drivers/net/rmnet/rmnet_map_data.c
@@ -0,0 +1,147 @@
+/* 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
+ * 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.
+ *
+ * RMNET Data MAP protocol
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/rmnet.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/time.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/udp.h>
+#include <linux/tcp.h>
+#include <linux/in.h>
+#include <net/ip.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include "rmnet_config.h"
+#include "rmnet_map.h"
+#include "rmnet_private.h"
+#include "rmnet_stats.h"
+
+RMNET_LOG_MODULE(RMNET_LOGMASK_MAPD);
+
+#define RMNET_MAP_DEAGGR_SPACING 64
+#define RMNET_MAP_DEAGGR_HEADROOM (RMNET_MAP_DEAGGR_SPACING / 2)
+
+/* rmnet_map_add_map_header() - Adds MAP header to front of skb->data
+ * @skb: Socket buffer ("packet") to modify
+ * @hdrlen: Number of bytes of header data which should not be included in
+ * MAP length field
+ * @pad: Specify if padding the MAP packet to make it 4 byte aligned is
+ * necessary
+ *
+ * Padding is calculated and set appropriately in MAP header. Mux ID is
+ * initialized to 0.
+ *
+ * Return:
+ * - Pointer to MAP structure
+ * - 0 (null) if insufficient headroom
+ * - 0 (null) if insufficient tailroom for padding bytes
+ *
+ * todo: Parameterize skb alignment
+ */
+struct rmnet_map_header_s *rmnet_map_add_map_header(struct sk_buff *skb,
+ int hdrlen, int pad)
+{
+ u32 padding, map_datalen;
+ u8 *padbytes;
+ struct rmnet_map_header_s *map_header;
+
+ if (skb_headroom(skb) < sizeof(struct rmnet_map_header_s))
+ return 0;
+
+ map_datalen = skb->len - hdrlen;
+ map_header = (struct rmnet_map_header_s *)
+ skb_push(skb, sizeof(struct rmnet_map_header_s));
+ memset(map_header, 0, sizeof(struct rmnet_map_header_s));
+
+ if (pad == RMNET_MAP_NO_PAD_BYTES) {
+ map_header->pkt_len = htons(map_datalen);
+ return map_header;
+ }
+
+ padding = ALIGN(map_datalen, 4) - map_datalen;
+
+ if (padding == 0)
+ goto done;
+
+ if (skb_tailroom(skb) < padding)
+ return 0;
+
+ padbytes = (u8 *)skb_put(skb, padding);
+ LOGD("pad: %d", padding);
+ memset(padbytes, 0, padding);
+
+done:
+ map_header->pkt_len = htons(map_datalen + padding);
+ map_header->pad_len = padding & 0x3F;
+
+ return map_header;
+}
+
+/* rmnet_map_deaggregate() - Deaggregates a single packet
+ * @skb: Source socket buffer containing multiple MAP frames
+ * @config: Physical endpoint configuration of the ingress device
+ *
+ * A whole new buffer is allocated for each portion of an aggregated frame.
+ * Caller should keep calling deaggregate() on the source skb until 0 is
+ * returned, indicating that there are no more packets to deaggregate. Caller
+ * is responsible for freeing the original skb.
+ *
+ * Return:
+ * - Pointer to new skb
+ * - 0 (null) if no more aggregated packets
+ */
+struct sk_buff *rmnet_map_deaggregate(struct sk_buff *skb,
+ struct rmnet_phys_ep_conf_s *config)
+{
+ struct sk_buff *skbn;
+ struct rmnet_map_header_s *maph;
+ u32 packet_len;
+
+ if (skb->len == 0)
+ return 0;
+
+ maph = (struct rmnet_map_header_s *)skb->data;
+ packet_len = ntohs(maph->pkt_len) + sizeof(struct rmnet_map_header_s);
+
+ if ((((int)skb->len) - ((int)packet_len)) < 0) {
+ LOGM("%s", "Got malformed packet. Dropping");
+ return 0;
+ }
+
+ skbn = alloc_skb(packet_len + RMNET_MAP_DEAGGR_SPACING, GFP_ATOMIC);
+ if (!skbn)
+ return 0;
+
+ skbn->dev = skb->dev;
+ skb_reserve(skbn, RMNET_MAP_DEAGGR_HEADROOM);
+ skb_put(skbn, packet_len);
+ memcpy(skbn->data, skb->data, packet_len);
+ skb_pull(skb, packet_len);
+
+ /* Some hardware can send us empty frames. Catch them */
+ if (ntohs(maph->pkt_len) == 0) {
+ LOGD("Dropping empty MAP frame");
+ rmnet_kfree_skb(skbn, RMNET_STATS_SKBFREE_DEAGG_DATA_LEN_0);
+ return 0;
+ }
+
+ return skbn;
+}
diff --git a/drivers/net/rmnet/rmnet_private.h b/drivers/net/rmnet/rmnet_private.h
new file mode 100644
index 000000000000..f27e0b3679cb
--- /dev/null
+++ b/drivers/net/rmnet/rmnet_private.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 2013-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
+ * 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 _RMNET_PRIVATE_H_
+#define _RMNET_PRIVATE_H_
+
+#define RMNET_MAX_VND 32
+#define RMNET_MAX_PACKET_SIZE 16384
+#define RMNET_DFLT_PACKET_SIZE 1500
+#define RMNET_DEV_NAME_STR "rmnet"
+#define RMNET_NEEDED_HEADROOM 16
+#define RMNET_TX_QUEUE_LEN 1000
+#define RMNET_ETHERNET_HEADER_LENGTH 14
+
+extern unsigned int rmnet_log_level;
+extern unsigned int rmnet_log_module_mask;
+
+#define RMNET_INIT_OK 0
+#define RMNET_INIT_ERROR 1
+
+#define RMNET_LOG_LVL_DBG BIT(4)
+#define RMNET_LOG_LVL_LOW BIT(3)
+#define RMNET_LOG_LVL_MED BIT(2)
+#define RMNET_LOG_LVL_HI BIT(1)
+#define RMNET_LOG_LVL_ERR BIT(0)
+
+#define RMNET_LOG_MODULE(X) \
+ static u32 rmnet_mod_mask = X
+
+#define RMNET_LOGMASK_CONFIG BIT(0)
+#define RMNET_LOGMASK_HANDLER BIT(1)
+#define RMNET_LOGMASK_VND BIT(2)
+#define RMNET_LOGMASK_MAPD BIT(3)
+#define RMNET_LOGMASK_MAPC BIT(4)
+
+#define LOGE(fmt, ...) do { if (rmnet_log_level & RMNET_LOG_LVL_ERR) \
+ pr_err("[RMNET:ERR] %s(): " fmt "\n", __func__, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#define LOGH(fmt, ...) do { if (rmnet_log_level & RMNET_LOG_LVL_HI) \
+ pr_err("[RMNET:HI] %s(): " fmt "\n", __func__, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#define LOGM(fmt, ...) do { if (rmnet_log_level & RMNET_LOG_LVL_MED) \
+ pr_warn("[RMNET:MED] %s(): " fmt "\n", __func__, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#define LOGL(fmt, ...) do { if (unlikely \
+ (rmnet_log_level & RMNET_LOG_LVL_LOW)) \
+ pr_notice("[RMNET:LOW] %s(): " fmt "\n", __func__, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+/* Don't use pr_debug as it is compiled out of the kernel. We can be sure of
+ * minimal impact as LOGD is not enabled by default.
+ */
+#define LOGD(fmt, ...) do { if (unlikely( \
+ (rmnet_log_level & RMNET_LOG_LVL_DBG) &&\
+ (rmnet_log_module_mask & rmnet_mod_mask))) \
+ pr_notice("[RMNET:DBG] %s(): " fmt "\n", __func__, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+#endif /* _RMNET_PRIVATE_H_ */
diff --git a/drivers/net/rmnet/rmnet_stats.c b/drivers/net/rmnet/rmnet_stats.c
new file mode 100644
index 000000000000..d53ce38e96fe
--- /dev/null
+++ b/drivers/net/rmnet/rmnet_stats.c
@@ -0,0 +1,86 @@
+/* Copyright (c) 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
+ * 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.
+ *
+ *
+ * RMNET Data statistics
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/netdevice.h>
+#include "rmnet_private.h"
+#include "rmnet_stats.h"
+#include "rmnet_config.h"
+#include "rmnet_map.h"
+
+enum rmnet_deagg_e {
+ RMNET_STATS_AGG_BUFF,
+ RMNET_STATS_AGG_PKT,
+ RMNET_STATS_AGG_MAX
+};
+
+static DEFINE_SPINLOCK(rmnet_skb_free_lock);
+unsigned long int skb_free[RMNET_STATS_SKBFREE_MAX];
+module_param_array(skb_free, ulong, 0, 0444);
+MODULE_PARM_DESC(skb_free, "SKBs dropped or freed");
+
+static DEFINE_SPINLOCK(rmnet_queue_xmit_lock);
+unsigned long int queue_xmit[RMNET_STATS_QUEUE_XMIT_MAX * 2];
+module_param_array(queue_xmit, ulong, 0, 0444);
+MODULE_PARM_DESC(queue_xmit, "SKBs queued for transmit");
+
+static DEFINE_SPINLOCK(rmnet_deagg_count);
+unsigned long int deagg_count[RMNET_STATS_AGG_MAX];
+module_param_array(deagg_count, ulong, 0, 0444);
+MODULE_PARM_DESC(deagg_count, "SKBs De-aggregated");
+
+void rmnet_kfree_skb(struct sk_buff *skb, unsigned int reason)
+{
+ unsigned long flags;
+
+ if (reason >= RMNET_STATS_SKBFREE_MAX)
+ reason = RMNET_STATS_SKBFREE_UNKNOWN;
+
+ spin_lock_irqsave(&rmnet_skb_free_lock, flags);
+ skb_free[reason]++;
+ spin_unlock_irqrestore(&rmnet_skb_free_lock, flags);
+
+ if (skb)
+ kfree_skb(skb);
+}
+
+void rmnet_stats_queue_xmit(int rc, unsigned int reason)
+{
+ unsigned long flags;
+
+ if (rc != 0)
+ reason += RMNET_STATS_QUEUE_XMIT_MAX;
+ if (reason >= RMNET_STATS_QUEUE_XMIT_MAX * 2)
+ reason = RMNET_STATS_SKBFREE_UNKNOWN;
+
+ spin_lock_irqsave(&rmnet_queue_xmit_lock, flags);
+ queue_xmit[reason]++;
+ spin_unlock_irqrestore(&rmnet_queue_xmit_lock, flags);
+}
+
+void rmnet_stats_deagg_pkts(int aggcount)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rmnet_deagg_count, flags);
+ deagg_count[RMNET_STATS_AGG_BUFF]++;
+ deagg_count[RMNET_STATS_AGG_PKT] += aggcount;
+ spin_unlock_irqrestore(&rmnet_deagg_count, flags);
+}
diff --git a/drivers/net/rmnet/rmnet_stats.h b/drivers/net/rmnet/rmnet_stats.h
new file mode 100644
index 000000000000..c8d0469bfe6a
--- /dev/null
+++ b/drivers/net/rmnet/rmnet_stats.h
@@ -0,0 +1,61 @@
+/* Copyright (c) 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
+ * 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.
+ *
+ *
+ * RMNET Data statistics
+ *
+ */
+
+#ifndef _RMNET_STATS_H_
+#define _RMNET_STATS_H_
+
+enum rmnet_skb_free_e {
+ RMNET_STATS_SKBFREE_UNKNOWN,
+ RMNET_STATS_SKBFREE_BRDG_NO_EGRESS,
+ RMNET_STATS_SKBFREE_DELIVER_NO_EP,
+ RMNET_STATS_SKBFREE_IPINGRESS_NO_EP,
+ RMNET_STATS_SKBFREE_MAPINGRESS_BAD_MUX,
+ RMNET_STATS_SKBFREE_MAPINGRESS_MUX_NO_EP,
+ RMNET_STATS_SKBFREE_MAPINGRESS_AGGBUF,
+ RMNET_STATS_SKBFREE_INGRESS_NOT_EXPECT_MAPD,
+ RMNET_STATS_SKBFREE_INGRESS_NOT_EXPECT_MAPC,
+ RMNET_STATS_SKBFREE_EGR_MAPFAIL,
+ RMNET_STATS_SKBFREE_VND_NO_EGRESS,
+ RMNET_STATS_SKBFREE_MAPC_BAD_MUX,
+ RMNET_STATS_SKBFREE_MAPC_MUX_NO_EP,
+ RMNET_STATS_SKBFREE_AGG_CPY_EXPAND,
+ RMNET_STATS_SKBFREE_AGG_INTO_BUFF,
+ RMNET_STATS_SKBFREE_DEAGG_MALFORMED,
+ RMNET_STATS_SKBFREE_DEAGG_CLONE_FAIL,
+ RMNET_STATS_SKBFREE_DEAGG_UNKNOWN_IP_TYPE,
+ RMNET_STATS_SKBFREE_DEAGG_DATA_LEN_0,
+ RMNET_STATS_SKBFREE_INGRESS_BAD_MAP_CKSUM,
+ RMNET_STATS_SKBFREE_MAPC_UNSUPPORTED,
+ RMNET_STATS_SKBFREE_MAX
+};
+
+enum rmnet_queue_xmit_e {
+ RMNET_STATS_QUEUE_XMIT_UNKNOWN,
+ RMNET_STATS_QUEUE_XMIT_EGRESS,
+ RMNET_STATS_QUEUE_XMIT_AGG_FILL_BUFFER,
+ RMNET_STATS_QUEUE_XMIT_AGG_TIMEOUT,
+ RMNET_STATS_QUEUE_XMIT_AGG_CPY_EXP_FAIL,
+ RMNET_STATS_QUEUE_XMIT_AGG_SKIP,
+ RMNET_STATS_QUEUE_XMIT_MAX
+};
+
+void rmnet_kfree_skb(struct sk_buff *skb, unsigned int reason);
+void rmnet_stats_queue_xmit(int rc, unsigned int reason);
+void rmnet_stats_deagg_pkts(int aggcount);
+void rmnet_stats_agg_pkts(int aggcount);
+void rmnet_stats_dl_checksum(unsigned int rc);
+void rmnet_stats_ul_checksum(unsigned int rc);
+#endif /* _RMNET_STATS_H_ */
diff --git a/drivers/net/rmnet/rmnet_vnd.c b/drivers/net/rmnet/rmnet_vnd.c
new file mode 100644
index 000000000000..a5b1cb891798
--- /dev/null
+++ b/drivers/net/rmnet/rmnet_vnd.c
@@ -0,0 +1,457 @@
+/* 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
+ * 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.
+ *
+ *
+ * RMNET Data virtual network driver
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/rmnet.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/spinlock.h>
+#include <net/pkt_sched.h>
+#include <linux/atomic.h>
+#include "rmnet_config.h"
+#include "rmnet_handlers.h"
+#include "rmnet_private.h"
+#include "rmnet_map.h"
+#include "rmnet_vnd.h"
+#include "rmnet_stats.h"
+
+RMNET_LOG_MODULE(RMNET_LOGMASK_VND);
+
+struct net_device *rmnet_devices[RMNET_MAX_VND];
+
+struct rmnet_vnd_private_s {
+ struct rmnet_logical_ep_conf_s local_ep;
+};
+
+/* RX/TX Fixup */
+
+/* rmnet_vnd_rx_fixup() - Virtual Network Device receive fixup hook
+ * @skb: Socket buffer ("packet") to modify
+ * @dev: Virtual network device
+ *
+ * Additional VND specific packet processing for ingress packets
+ *
+ * Return:
+ * - RX_HANDLER_PASS if packet should continue to process in stack
+ * - RX_HANDLER_CONSUMED if packet should not be processed in stack
+ *
+ */
+int rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev)
+{
+ if (unlikely(!dev || !skb))
+ return RX_HANDLER_CONSUMED;
+
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
+
+ return RX_HANDLER_PASS;
+}
+
+/* rmnet_vnd_tx_fixup() - Virtual Network Device transmic fixup hook
+ * @skb: Socket buffer ("packet") to modify
+ * @dev: Virtual network device
+ *
+ * Additional VND specific packet processing for egress packets
+ *
+ * Return:
+ * - RX_HANDLER_PASS if packet should continue to be transmitted
+ * - RX_HANDLER_CONSUMED if packet should not be transmitted by stack
+ */
+int rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev)
+{
+ struct rmnet_vnd_private_s *dev_conf;
+
+ dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev);
+
+ if (unlikely(!dev || !skb))
+ return RX_HANDLER_CONSUMED;
+
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+
+ return RX_HANDLER_PASS;
+}
+
+/* Network Device Operations */
+
+/* rmnet_vnd_start_xmit() - Transmit NDO callback
+ * @skb: Socket buffer ("packet") being sent from network stack
+ * @dev: Virtual Network Device
+ *
+ * Standard network driver operations hook to transmit packets on virtual
+ * network device. Called by network stack. Packet is not transmitted directly
+ * from here; instead it is given to the rmnet egress handler.
+ *
+ * Return:
+ * - NETDEV_TX_OK under all cirumstances (cannot block/fail)
+ */
+static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct rmnet_vnd_private_s *dev_conf;
+
+ dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev);
+ if (dev_conf->local_ep.egress_dev) {
+ rmnet_egress_handler(skb, &dev_conf->local_ep);
+ } else {
+ dev->stats.tx_dropped++;
+ rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_VND_NO_EGRESS);
+ }
+ return NETDEV_TX_OK;
+}
+
+/* rmnet_vnd_change_mtu() - Change MTU NDO callback
+ * @dev: Virtual network device
+ * @new_mtu: New MTU value to set (in bytes)
+ *
+ * Standard network driver operations hook to set the MTU. Called by kernel to
+ * set the device MTU. Checks if desired MTU is less than zero or greater than
+ * RMNET_MAX_PACKET_SIZE;
+ *
+ * Return:
+ * - 0 if successful
+ * - -EINVAL if new_mtu is out of range
+ */
+static int rmnet_vnd_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (new_mtu < 0 || new_mtu > RMNET_MAX_PACKET_SIZE)
+ return -EINVAL;
+
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+static const struct net_device_ops rmnet_vnd_ops = {
+ .ndo_init = 0,
+ .ndo_start_xmit = rmnet_vnd_start_xmit,
+ .ndo_change_mtu = rmnet_vnd_change_mtu,
+ .ndo_set_mac_address = 0,
+ .ndo_validate_addr = 0,
+};
+
+/* rmnet_vnd_setup() - net_device initialization callback
+ * @dev: Virtual network device
+ *
+ * Called by kernel whenever a new rmnet<n> device is created. Sets MTU,
+ * flags, ARP type, needed headroom, etc...
+ */
+static void rmnet_vnd_setup(struct net_device *dev)
+{
+ struct rmnet_vnd_private_s *dev_conf;
+
+ LOGM("Setting up device %s", dev->name);
+
+ /* Clear out private data */
+ dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev);
+ memset(dev_conf, 0, sizeof(struct rmnet_vnd_private_s));
+
+ dev->netdev_ops = &rmnet_vnd_ops;
+ dev->mtu = RMNET_DFLT_PACKET_SIZE;
+ dev->needed_headroom = RMNET_NEEDED_HEADROOM;
+ random_ether_addr(dev->dev_addr);
+ dev->tx_queue_len = RMNET_TX_QUEUE_LEN;
+
+ /* Raw IP mode */
+ dev->header_ops = 0; /* No header */
+ dev->type = ARPHRD_RAWIP;
+ dev->hard_header_len = 0;
+ dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
+}
+
+/* Exposed API */
+
+/* rmnet_vnd_exit() - Shutdown cleanup hook
+ *
+ * Called by RmNet main on module unload. Cleans up data structures and
+ * unregisters/frees net_devices.
+ */
+void rmnet_vnd_exit(void)
+{
+ int i;
+
+ for (i = 0; i < RMNET_MAX_VND; i++)
+ if (rmnet_devices[i]) {
+ unregister_netdev(rmnet_devices[i]);
+ free_netdev(rmnet_devices[i]);
+ }
+}
+
+/* rmnet_vnd_init() - Init hook
+ *
+ * Called by RmNet main on module load. Initializes data structures
+ */
+int rmnet_vnd_init(void)
+{
+ memset(rmnet_devices, 0,
+ sizeof(struct net_device *) * RMNET_MAX_VND);
+ return 0;
+}
+
+/* rmnet_vnd_create_dev() - Create a new virtual network device node.
+ * @id: Virtual device node id
+ * @new_device: Pointer to newly created device node
+ * @prefix: Device name prefix
+ *
+ * Allocates structures for new virtual network devices. Sets the name of the
+ * new device and registers it with the network stack. Device will appear in
+ * ifconfig list after this is called. If the prefix is null, then
+ * RMNET_DEV_NAME_STR will be assumed.
+ *
+ * Return:
+ * - 0 if successful
+ * - RMNET_CONFIG_BAD_ARGUMENTS if id is out of range or prefix is too long
+ * - RMNET_CONFIG_DEVICE_IN_USE if id already in use
+ * - RMNET_CONFIG_NOMEM if net_device allocation failed
+ * - RMNET_CONFIG_UNKNOWN_ERROR if register_netdevice() fails
+ */
+int rmnet_vnd_create_dev(int id, struct net_device **new_device,
+ const char *prefix)
+{
+ struct net_device *dev;
+ char dev_prefix[IFNAMSIZ];
+ int p, rc = 0;
+
+ if (id < 0 || id >= RMNET_MAX_VND) {
+ *new_device = 0;
+ return RMNET_CONFIG_BAD_ARGUMENTS;
+ }
+
+ if (rmnet_devices[id]) {
+ *new_device = 0;
+ return RMNET_CONFIG_DEVICE_IN_USE;
+ }
+
+ if (!prefix)
+ p = scnprintf(dev_prefix, IFNAMSIZ, "%s%%d",
+ RMNET_DEV_NAME_STR);
+ else
+ p = scnprintf(dev_prefix, IFNAMSIZ, "%s%%d", prefix);
+ if (p >= (IFNAMSIZ - 1)) {
+ LOGE("Specified prefix longer than IFNAMSIZ");
+ return RMNET_CONFIG_BAD_ARGUMENTS;
+ }
+
+ dev = alloc_netdev(sizeof(struct rmnet_vnd_private_s),
+ dev_prefix,
+ NET_NAME_ENUM,
+ rmnet_vnd_setup);
+ if (!dev) {
+ LOGE("Failed to to allocate netdev for id %d", id);
+ *new_device = 0;
+ return RMNET_CONFIG_NOMEM;
+ }
+
+ rc = register_netdevice(dev);
+ if (rc != 0) {
+ LOGE("Failed to to register netdev [%s]", dev->name);
+ free_netdev(dev);
+ *new_device = 0;
+ rc = RMNET_CONFIG_UNKNOWN_ERROR;
+ } else {
+ rmnet_devices[id] = dev;
+ *new_device = dev;
+ LOGM("Registered device %s", dev->name);
+ }
+
+ return rc;
+}
+
+/* rmnet_vnd_free_dev() - free a virtual network device node.
+ * @id: Virtual device node id
+ *
+ * Unregisters the virtual network device node and frees it.
+ * unregister_netdev locks the rtnl mutex, so the mutex must not be locked
+ * by the caller of the function. unregister_netdev enqueues the request to
+ * unregister the device into a TODO queue. The requests in the TODO queue
+ * are only done after rtnl mutex is unlocked, therefore free_netdev has to
+ * called after unlocking rtnl mutex.
+ *
+ * Return:
+ * - 0 if successful
+ * - RMNET_CONFIG_NO_SUCH_DEVICE if id is invalid or not in range
+ * - RMNET_CONFIG_DEVICE_IN_USE if device has logical ep that wasn't unset
+ */
+int rmnet_vnd_free_dev(int id)
+{
+ struct rmnet_logical_ep_conf_s *epconfig_l;
+ struct net_device *dev;
+
+ rtnl_lock();
+ if ((id < 0) || (id >= RMNET_MAX_VND) || !rmnet_devices[id]) {
+ rtnl_unlock();
+ LOGM("Invalid id [%d]", id);
+ return RMNET_CONFIG_NO_SUCH_DEVICE;
+ }
+
+ epconfig_l = rmnet_vnd_get_le_config(rmnet_devices[id]);
+ if (epconfig_l && epconfig_l->refcount) {
+ rtnl_unlock();
+ return RMNET_CONFIG_DEVICE_IN_USE;
+ }
+
+ dev = rmnet_devices[id];
+ rmnet_devices[id] = 0;
+ rtnl_unlock();
+
+ if (dev) {
+ unregister_netdev(dev);
+ free_netdev(dev);
+ return 0;
+ } else {
+ return RMNET_CONFIG_NO_SUCH_DEVICE;
+ }
+}
+
+/* rmnet_vnd_get_name() - Gets the string name of a VND based on ID
+ * @id: Virtual device node id
+ * @name: Buffer to store name of virtual device node
+ * @name_len: Length of name buffer
+ *
+ * Copies the name of the virtual device node into the users buffer. Will throw
+ * an error if the buffer is null, or too small to hold the device name.
+ *
+ * Return:
+ * - 0 if successful
+ * - -EINVAL if name is null
+ * - -EINVAL if id is invalid or not in range
+ * - -EINVAL if name is too small to hold things
+ */
+int rmnet_vnd_get_name(int id, char *name, int name_len)
+{
+ int p;
+
+ if (!name) {
+ LOGM("%s", "Bad arguments; name buffer null");
+ return -EINVAL;
+ }
+
+ if ((id < 0) || (id >= RMNET_MAX_VND) || !rmnet_devices[id]) {
+ LOGM("Invalid id [%d]", id);
+ return -EINVAL;
+ }
+
+ p = strlcpy(name, rmnet_devices[id]->name, name_len);
+ if (p >= name_len) {
+ LOGM("Buffer to small (%d) to fit device name", name_len);
+ return -EINVAL;
+ }
+ LOGL("Found mapping [%d]->\"%s\"", id, name);
+
+ return 0;
+}
+
+/* rmnet_vnd_is_vnd() - Determine if net_device is RmNet owned virtual devices
+ * @dev: Network device to test
+ *
+ * Searches through list of known RmNet virtual devices. This function is O(n)
+ * and should not be used in the data path.
+ *
+ * Return:
+ * - 0 if device is not RmNet virtual device
+ * - 1 if device is RmNet virtual device
+ */
+int rmnet_vnd_is_vnd(struct net_device *dev)
+{
+ /* This is not an efficient search, but, this will only be called in
+ * a configuration context, and the list is small.
+ */
+ int i;
+
+ if (!dev)
+ return 0;
+
+ for (i = 0; i < RMNET_MAX_VND; i++)
+ if (dev == rmnet_devices[i])
+ return i + 1;
+
+ return 0;
+}
+
+/* rmnet_vnd_get_le_config() - Get the logical endpoint configuration
+ * @dev: Virtual device node
+ *
+ * Gets the logical endpoint configuration for a RmNet virtual network device
+ * node. Caller should confirm that devices is a RmNet VND before calling.
+ *
+ * Return:
+ * - Pointer to logical endpoint configuration structure
+ * - 0 (null) if dev is null
+ */
+struct rmnet_logical_ep_conf_s *rmnet_vnd_get_le_config(struct net_device *dev)
+{
+ struct rmnet_vnd_private_s *dev_conf;
+
+ if (!dev)
+ return 0;
+
+ dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev);
+ if (!dev_conf)
+ return 0;
+
+ return &dev_conf->local_ep;
+}
+
+/* rmnet_vnd_do_flow_control() - Process flow control request
+ * @dev: Virtual network device node to do lookup on
+ * @enable: boolean to enable/disable flow.
+ *
+ * Return:
+ * - 0 if successful
+ * - -EINVAL if dev is not RmNet virtual network device node
+ */
+int rmnet_vnd_do_flow_control(struct net_device *dev, int enable)
+{
+ struct rmnet_vnd_private_s *dev_conf;
+
+ if (unlikely(!dev))
+ return -EINVAL;
+
+ if (!rmnet_vnd_is_vnd(dev))
+ return -EINVAL;
+
+ dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev);
+
+ if (unlikely(!dev_conf))
+ return -EINVAL;
+
+ LOGD("Setting VND TX queue state to %d", enable);
+ /* Although we expect similar number of enable/disable
+ * commands, optimize for the disable. That is more
+ * latency sensitive than enable
+ */
+ if (unlikely(enable))
+ netif_wake_queue(dev);
+ else
+ netif_stop_queue(dev);
+
+ return 0;
+}
+
+/* rmnet_vnd_get_by_id() - Get VND by array index ID
+ * @id: Virtual network deice id [0:RMNET_MAX_VND]
+ *
+ * Return:
+ * - 0 if no device or ID out of range
+ * - otherwise return pointer to VND net_device struct
+ */
+struct net_device *rmnet_vnd_get_by_id(int id)
+{
+ if (id < 0 || id >= RMNET_MAX_VND) {
+ pr_err("Bug; VND ID out of bounds");
+ return 0;
+ }
+ return rmnet_devices[id];
+}
diff --git a/drivers/net/rmnet/rmnet_vnd.h b/drivers/net/rmnet/rmnet_vnd.h
new file mode 100644
index 000000000000..428240898ff0
--- /dev/null
+++ b/drivers/net/rmnet/rmnet_vnd.h
@@ -0,0 +1,34 @@
+/* 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
+ * 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.
+ *
+ * RMNET Data Virtual Network Device APIs
+ *
+ */
+
+#include <linux/types.h>
+
+#ifndef _RMNET_VND_H_
+#define _RMNET_VND_H_
+
+int rmnet_vnd_do_flow_control(struct net_device *dev, int enable);
+struct rmnet_logical_ep_conf_s *rmnet_vnd_get_le_config(struct net_device *dev);
+int rmnet_vnd_get_name(int id, char *name, int name_len);
+int rmnet_vnd_create_dev(int id, struct net_device **new_device,
+ const char *prefix);
+int rmnet_vnd_free_dev(int id);
+int rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev);
+int rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev);
+int rmnet_vnd_is_vnd(struct net_device *dev);
+int rmnet_vnd_init(void);
+void rmnet_vnd_exit(void);
+struct net_device *rmnet_vnd_get_by_id(int id);
+
+#endif /* _RMNET_VND_H_ */
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index dd7b7d64c90a..a444294fb555 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1105,9 +1105,11 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
}
if (tun->flags & IFF_VNET_HDR) {
- if (len < tun->vnet_hdr_sz)
+ int vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz);
+
+ if (len < vnet_hdr_sz)
return -EINVAL;
- len -= tun->vnet_hdr_sz;
+ len -= vnet_hdr_sz;
n = copy_from_iter(&gso, sizeof(gso), from);
if (n != sizeof(gso))
@@ -1119,7 +1121,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
if (tun16_to_cpu(tun, gso.hdr_len) > len)
return -EINVAL;
- iov_iter_advance(from, tun->vnet_hdr_sz - sizeof(gso));
+ iov_iter_advance(from, vnet_hdr_sz - sizeof(gso));
}
if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) {
@@ -1302,7 +1304,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
vlan_hlen = VLAN_HLEN;
if (tun->flags & IFF_VNET_HDR)
- vnet_hdr_sz = tun->vnet_hdr_sz;
+ vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz);
total = skb->len + vlan_hlen + vnet_hdr_sz;
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 284caf81e808..486af5dac5df 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -332,5 +332,6 @@ source "drivers/net/wireless/mwifiex/Kconfig"
source "drivers/net/wireless/cw1200/Kconfig"
source "drivers/net/wireless/rsi/Kconfig"
source "drivers/net/wireless/cnss/Kconfig"
+source "drivers/net/wireless/cnss_genl/Kconfig"
endif # WLAN
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 818fa279b25d..0204fc00f0c5 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -66,3 +66,4 @@ obj-$(CONFIG_WCNSS_CORE) += wcnss/
obj-$(CONFIG_CNSS) += cnss/
obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
obj-$(CONFIG_CNSS_CRYPTO) += cnss_crypto/
+obj-$(CONFIG_CNSS_GENL) += cnss_genl/
diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index 25b23bf2c8e6..27a6c75682c4 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -26,6 +26,8 @@ ath10k_pci-y += pci.o \
ce.o
obj-$(CONFIG_ATH10K_TARGET_SNOC) += ath10k_snoc.o
ath10k_snoc-y += snoc.o \
+ qmi.o \
+ wcn3990_qmi_service_v01.o \
ce.o
ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index b8a3a1ecabaa..9cda1303c9e1 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -455,6 +455,9 @@ int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
u32 desc_flags = 0;
int ret = 0;
+ if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
+ return -ESHUTDOWN;
+
if (nbytes > ce_state->src_sz_max)
ath10k_warn(ar, "%s: send more we can (nbytes: %d, max: %d)\n",
__func__, nbytes, ce_state->src_sz_max);
@@ -942,6 +945,9 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar)
struct ath10k_ce_pipe *ce_state;
struct bus_opaque *ar_opaque = ath10k_bus_priv(ar);
+ if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
+ return;
+
if (ar->target_version == ATH10K_HW_WCN3990)
intr_summary = 0xFFF;
else
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index d37ed66d767b..9acaffa51516 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1536,7 +1536,6 @@ static void ath10k_core_restart(struct work_struct *work)
struct ath10k *ar = container_of(work, struct ath10k, restart_work);
set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);
- ath10k_gen_set_base_mac_addr(ar, ar->base_mac_addr);
/* Place a barrier to make sure the compiler doesn't reorder
* CRASH_FLUSH and calling other functions.
@@ -2390,6 +2389,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
mutex_init(&ar->conf_mutex);
spin_lock_init(&ar->data_lock);
spin_lock_init(&ar->txqs_lock);
+ spin_lock_init(&ar->datapath_rx_stat_lock);
INIT_LIST_HEAD(&ar->txqs);
INIT_LIST_HEAD(&ar->peers);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index a20ac680cfb9..01d5ecc4f6b8 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -70,6 +70,20 @@
#define ATH10K_NAPI_BUDGET 64
#define ATH10K_NAPI_QUOTA_LIMIT 60
+#define ATH10K_RX_MCS_MIN 0
+#define ATH10K_RX_HT_MCS_MAX 32
+#define ATH10K_RX_VHT_RATEIDX_MAX 9
+#define ATH10K_RX_VHT_MCS_MAX 20 /* For 2x2 */
+#define ATH10K_RX_NSS_MIN 0
+#define ATH10K_RX_NSS_MAX 5
+
+enum ath10k_datapath_rx_band {
+ ATH10K_BAND_MIN,
+ ATH10K_BAND_2GHZ = ATH10K_BAND_MIN,
+ ATH10K_BAND_5GHZ,
+ ATH10K_BAND_MAX,
+};
+
struct ath10k;
enum ath10k_bus {
@@ -703,6 +717,20 @@ struct ath10k_fw_components {
struct ath10k_fw_file fw_file;
};
+struct datapath_rx_stats {
+ u32 no_of_packets;
+ u32 short_gi_pkts;
+ u32 ht_rate_indx[ATH10K_RX_HT_MCS_MAX + 1];
+ u32 vht_rate_indx[ATH10K_RX_VHT_MCS_MAX + 1];
+ u32 ht_rate_packets;
+ u32 vht_rate_packets;
+ u32 legacy_pkt;
+ u32 nss[ATH10K_RX_NSS_MAX + 1];
+ u32 num_pkts_40Mhz;
+ u32 num_pkts_80Mhz;
+ u32 band[ATH10K_BAND_MAX + 1];
+};
+
struct ath10k {
struct ath_common ath_common;
struct ieee80211_hw *hw;
@@ -900,7 +928,10 @@ struct ath10k {
enum ath10k_spectral_mode mode;
struct ath10k_spec_scan config;
} spectral;
+ struct datapath_rx_stats *rx_stats;
#endif
+ /* prevent concurrency histogram for receiving data packet */
+ spinlock_t datapath_rx_stat_lock;
struct {
/* protected by conf_mutex */
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 8d97822cbbde..ec8063e7986a 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -537,6 +537,230 @@ static const struct file_operations fops_fw_stats = {
.llseek = default_llseek,
};
+static inline int is_vht_rate_valid(u32 rate_indx)
+{
+ if ((rate_indx >= ATH10K_RX_MCS_MIN) &&
+ (rate_indx <= ATH10K_RX_VHT_RATEIDX_MAX))
+ return 1;
+ else
+ return 0;
+}
+
+void fill_datapath_stats(struct ath10k *ar, struct ieee80211_rx_status *status)
+{
+ struct datapath_rx_stats *stat_cnt = ar->rx_stats;
+
+ spin_lock_bh(&ar->datapath_rx_stat_lock);
+
+ stat_cnt->no_of_packets += 1;
+ if (!(stat_cnt->no_of_packets)) {
+ memset(stat_cnt, 0, sizeof(*stat_cnt));
+ stat_cnt->no_of_packets += 1;
+ }
+
+ if (status->flag & RX_FLAG_SHORT_GI)
+ stat_cnt->short_gi_pkts += 1;
+
+ if ((status->vht_nss >= ATH10K_RX_NSS_MIN) &&
+ (status->vht_nss < ATH10K_RX_NSS_MAX)) {
+ stat_cnt->nss[status->vht_nss] += 1;
+ if (status->flag & RX_FLAG_VHT) {
+ stat_cnt->vht_rate_packets += 1;
+ if (is_vht_rate_valid(status->rate_idx)) {
+ stat_cnt->vht_rate_indx[((status->vht_nss - 1) *
+ 10) + status->rate_idx] += 1;
+ } else {
+ /*if we get index other than (>=0 and <=9)*/
+ stat_cnt->vht_rate_indx[ATH10K_RX_VHT_MCS_MAX] += 1;
+ }
+ } else if (status->flag & RX_FLAG_HT) {
+ stat_cnt->ht_rate_packets += 1;
+ if ((status->rate_idx >= ATH10K_RX_MCS_MIN) &&
+ (status->rate_idx < ATH10K_RX_HT_MCS_MAX))
+ stat_cnt->ht_rate_indx[status->rate_idx] += 1;
+ else {
+ /*if we get index other than (>=0 and <=31)*/
+ stat_cnt->ht_rate_indx[ATH10K_RX_HT_MCS_MAX] += 1;
+ }
+ } else {
+ /* if pkt is other than HT and VHT */
+ stat_cnt->legacy_pkt += 1;
+ }
+ } else {
+ stat_cnt->nss[ATH10K_RX_NSS_MAX] += 1;
+ }
+
+ if (status->flag & RX_FLAG_40MHZ)
+ stat_cnt->num_pkts_40Mhz += 1;
+ if (status->vht_flag & RX_VHT_FLAG_80MHZ)
+ stat_cnt->num_pkts_80Mhz += 1;
+ if ((status->band >= ATH10K_BAND_MIN) &&
+ (status->band < ATH10K_BAND_MAX)) {
+ stat_cnt->band[status->band] += 1;
+ } else {
+ /*if band is other than 0,1 */
+ stat_cnt->band[ATH10K_BAND_MAX] += 1;
+ }
+
+ spin_unlock_bh(&ar->datapath_rx_stat_lock);
+}
+
+size_t get_datapath_stat(char *buf, struct ath10k *ar)
+{
+ u8 i;
+ struct datapath_rx_stats *stat_cnt = ar->rx_stats;
+ size_t j = 0;
+
+ spin_lock(&ar->datapath_rx_stat_lock);
+
+ j = snprintf(buf, ATH10K_DATAPATH_BUF_SIZE, "\nNo of packets: %u\t"
+ "No of short_gi packets: %u\n"
+ "\nHT Packets: %u \t VHT Packets: %u\n"
+ "\n40Mhz Packets: %u \t 80Mhz Packets: %u\n"
+ "\n2.4GHz: %u \t 5GHz: %u \t band-error: %u\n\n",
+ stat_cnt->no_of_packets,
+ stat_cnt->short_gi_pkts,
+ stat_cnt->ht_rate_packets,
+ stat_cnt->vht_rate_packets,
+ stat_cnt->num_pkts_40Mhz,
+ stat_cnt->num_pkts_80Mhz,
+ stat_cnt->band[ATH10K_BAND_2GHZ],
+ stat_cnt->band[ATH10K_BAND_5GHZ],
+ stat_cnt->band[ATH10K_BAND_MAX]);
+
+ for (i = 0; i <= ATH10K_RX_NSS_MAX; i++) {
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "NSS-%u: %u\t", i, stat_cnt->nss[i]);
+ }
+
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "\n\n----HT Rate index------\n");
+
+ for (i = ATH10K_RX_MCS_MIN; i < ATH10K_RX_HT_MCS_MAX;
+ i += 4) {
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "ht_rate_indx[%02u]: %10u\tht_rate_indx[%02u]: %10u\t"
+ "ht_rate_indx[%02u]: %10u\tht_rate_indx[%02u]: %10u\n",
+ i, stat_cnt->ht_rate_indx[i],
+ i + 1, stat_cnt->ht_rate_indx[i + 1],
+ i + 2, stat_cnt->ht_rate_indx[i + 2],
+ i + 3, stat_cnt->ht_rate_indx[i + 3]);
+ }
+
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "ht_rate_indx[OOB]: %10u\n",
+ stat_cnt->ht_rate_indx[ATH10K_RX_HT_MCS_MAX]);
+
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "\n----VHT Rate index------\n");
+
+ for (i = ATH10K_RX_MCS_MIN;
+ i <= ATH10K_RX_VHT_RATEIDX_MAX; i++) {
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "vht_rate_indx[%02u]: %10u\tvht_rate_indx[%02u]: %10u\n",
+ i, stat_cnt->vht_rate_indx[i],
+ i + 10, stat_cnt->vht_rate_indx[i + 10]);
+ }
+
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "vht_rate_indx[%02u]: %10u\n",
+ i + 10, stat_cnt->vht_rate_indx[i + 10]);
+
+ j += snprintf(buf + j, (ATH10K_DATAPATH_BUF_SIZE - j),
+ "\nnumber of pkt other than HT and VHT(legacy) : %u\n"
+ "----------------------\n",
+ stat_cnt->legacy_pkt);
+
+ spin_unlock(&ar->datapath_rx_stat_lock);
+
+ return j;
+}
+
+static int ath10k_datapath_stats_open(struct inode *inode, struct file *file)
+{
+ struct ath10k *ar = inode->i_private;
+ int ret;
+
+ spin_lock(&ar->datapath_rx_stat_lock);
+
+ if (ar->state != ATH10K_STATE_ON) {
+ ret = -ENETDOWN;
+ goto err_unlock;
+ }
+
+ file->private_data = ar;
+
+ spin_unlock(&ar->datapath_rx_stat_lock);
+ return 0;
+
+err_unlock:
+ spin_unlock(&ar->datapath_rx_stat_lock);
+ return ret;
+}
+
+static ssize_t ath10k_datapath_stats_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ size_t buf_len;
+ unsigned int ret;
+ void *buf = NULL;
+
+ buf = vmalloc(ATH10K_DATAPATH_BUF_SIZE);
+ if (!buf)
+ return 0;
+
+ buf_len = get_datapath_stat(buf, ar);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, buf_len);
+ vfree(buf);
+
+ return ret;
+}
+
+static ssize_t ath10k_datapath_stats_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ u32 filter;
+ int ret;
+
+ if (kstrtouint_from_user(ubuf, count, 0, &filter))
+ return -EINVAL;
+
+ spin_lock(&ar->datapath_rx_stat_lock);
+
+ if (ar->state != ATH10K_STATE_ON) {
+ ret = count;
+ goto err_unlock;
+ }
+
+ if (!filter)
+ memset(ar->rx_stats, 0, sizeof(*ar->rx_stats));
+
+ ret = count;
+
+err_unlock:
+ spin_unlock(&ar->datapath_rx_stat_lock);
+ return ret;
+}
+
+static int ath10k_datapath_stats_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static const struct file_operations fops_datapath_stats = {
+ .open = ath10k_datapath_stats_open,
+ .read = ath10k_datapath_stats_read,
+ .write = ath10k_datapath_stats_write,
+ .release = ath10k_datapath_stats_release,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
static ssize_t ath10k_debug_fw_reset_stats_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@@ -2401,7 +2625,11 @@ int ath10k_debug_create(struct ath10k *ar)
ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
if (!ar->debug.cal_data)
- return -ENOMEM;
+ goto err_cal_data;
+
+ ar->rx_stats = vzalloc(sizeof(*ar->rx_stats));
+ if (!ar->rx_stats)
+ goto err_rx_stats;
INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
@@ -2409,6 +2637,13 @@ int ath10k_debug_create(struct ath10k *ar)
INIT_LIST_HEAD(&ar->debug.fw_stats.peers_extd);
return 0;
+
+err_rx_stats:
+ vfree(ar->debug.cal_data);
+
+err_cal_data:
+ vfree(ar->debug.fw_crash_data);
+ return -ENOMEM;
}
void ath10k_debug_destroy(struct ath10k *ar)
@@ -2419,6 +2654,9 @@ void ath10k_debug_destroy(struct ath10k *ar)
vfree(ar->debug.cal_data);
ar->debug.cal_data = NULL;
+ vfree(ar->rx_stats);
+ ar->rx_stats = NULL;
+
ath10k_debug_fw_stats_reset(ar);
kfree(ar->debug.tpc_stats);
@@ -2441,6 +2679,9 @@ int ath10k_debug_register(struct ath10k *ar)
init_completion(&ar->debug.tpc_complete);
init_completion(&ar->debug.fw_stats_complete);
+ debugfs_create_file("datapath_rx_stats", S_IRUSR, ar->debug.debugfs_phy,
+ ar, &fops_datapath_stats);
+
debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar,
&fops_fw_stats);
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index b1db01a167ac..f963391e3544 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -38,7 +38,7 @@ enum ath10k_debug_mask {
ATH10K_DBG_WMI_PRINT = 0x00002000,
ATH10K_DBG_PCI_PS = 0x00004000,
ATH10K_DBG_AHB = 0x00008000,
- ATH10K_DBG_SNOC = 0x00009000,
+ ATH10K_DBG_SNOC = 0x00010000,
ATH10K_DBG_ANY = 0xffffffff,
};
@@ -59,6 +59,7 @@ enum ath10k_dbg_aggr_mode {
/* FIXME: How to calculate the buffer size sanely? */
#define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024)
+#define ATH10K_DATAPATH_BUF_SIZE (1024 * 1024)
extern unsigned int ath10k_debug_mask;
@@ -95,6 +96,8 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ethtool_stats *stats, u64 *data);
+void fill_datapath_stats(struct ath10k *ar, struct ieee80211_rx_status *status);
+size_t get_datapath_stat(char *buf, struct ath10k *ar);
#else
static inline int ath10k_debug_start(struct ath10k *ar)
{
@@ -145,6 +148,16 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
return NULL;
}
+static inline void fill_datapath_stats(struct ath10k *ar,
+ struct ieee80211_rx_status *status)
+{
+}
+
+static inline size_t get_datapath_stat(char *buf, struct ath10k *ar)
+{
+ return 0;
+}
+
#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
#define ath10k_debug_get_et_strings NULL
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index ddf097e3a143..437ea2c192b3 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -940,7 +940,7 @@ static void ath10k_process_rx(struct ath10k *ar,
status = IEEE80211_SKB_RXCB(skb);
*status = *rx_status;
-
+ fill_datapath_stats(ar, status);
ath10k_dbg(ar, ATH10K_DBG_DATA,
"rx skb %pK len %u peer %pM %s %s sn %u %s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n",
skb,
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 265744c75f82..35e5d980ed49 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4450,7 +4450,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
ar->state = ATH10K_STATE_ON;
break;
case ATH10K_STATE_RESTARTING:
- ath10k_halt(ar);
+ if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
+ ath10k_halt(ar);
ar->state = ATH10K_STATE_RESTARTED;
break;
case ATH10K_STATE_ON:
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
new file mode 100644
index 000000000000..7d20f087da71
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -0,0 +1,865 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <soc/qcom/subsystem_notif.h>
+#include <soc/qcom/subsystem_restart.h>
+#include <soc/qcom/service-notifier.h>
+#include <soc/qcom/msm_qmi_interface.h>
+#include <soc/qcom/service-locator.h>
+#include "core.h"
+#include "qmi.h"
+#include "snoc.h"
+#include "wcn3990_qmi_service_v01.h"
+
+static DECLARE_WAIT_QUEUE_HEAD(ath10k_fw_ready_wait_event);
+
+static int
+ath10k_snoc_service_notifier_notify(struct notifier_block *nb,
+ unsigned long notification, void *data)
+{
+ struct ath10k_snoc *ar_snoc = container_of(nb, struct ath10k_snoc,
+ service_notifier_nb);
+ enum pd_subsys_state *state = data;
+ struct ath10k *ar = ar_snoc->ar;
+
+ switch (notification) {
+ case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01:
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "Service down, data: 0x%pK\n",
+ data);
+
+ if (!state || *state != ROOT_PD_SHUTDOWN)
+ atomic_set(&ar_snoc->fw_crashed, 1);
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "PD went down %d\n",
+ atomic_read(&ar_snoc->fw_crashed));
+ break;
+ case SERVREG_NOTIF_SERVICE_STATE_UP_V01:
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "Service up\n");
+ queue_work(ar->workqueue, &ar->restart_work);
+ break;
+ default:
+ ath10k_dbg(ar, ATH10K_DBG_SNOC,
+ "Service state Unknown, notification: 0x%lx\n",
+ notification);
+ return NOTIFY_DONE;
+ }
+ return NOTIFY_OK;
+}
+
+static int ath10k_snoc_get_service_location_notify(struct notifier_block *nb,
+ unsigned long opcode,
+ void *data)
+{
+ struct ath10k_snoc *ar_snoc = container_of(nb, struct ath10k_snoc,
+ get_service_nb);
+ struct ath10k *ar = ar_snoc->ar;
+ struct pd_qmi_client_data *pd = data;
+ int curr_state;
+ int ret;
+ int i;
+ struct ath10k_service_notifier_context *notifier;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "Get service notify opcode: %lu\n",
+ opcode);
+
+ if (opcode != LOCATOR_UP)
+ return NOTIFY_DONE;
+
+ if (!pd->total_domains) {
+ ath10k_err(ar, "Did not find any domains\n");
+ ret = -ENOENT;
+ goto out;
+ }
+
+ notifier = kcalloc(pd->total_domains,
+ sizeof(struct ath10k_service_notifier_context),
+ GFP_KERNEL);
+ if (!notifier) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ar_snoc->service_notifier_nb.notifier_call =
+ ath10k_snoc_service_notifier_notify;
+
+ for (i = 0; i < pd->total_domains; i++) {
+ ath10k_dbg(ar, ATH10K_DBG_SNOC,
+ "%d: domain_name: %s, instance_id: %d\n", i,
+ pd->domain_list[i].name,
+ pd->domain_list[i].instance_id);
+
+ notifier[i].handle =
+ service_notif_register_notifier(
+ pd->domain_list[i].name,
+ pd->domain_list[i].instance_id,
+ &ar_snoc->service_notifier_nb,
+ &curr_state);
+ notifier[i].instance_id = pd->domain_list[i].instance_id;
+ strlcpy(notifier[i].name, pd->domain_list[i].name,
+ QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1);
+
+ if (IS_ERR(notifier[i].handle)) {
+ ath10k_err(ar, "%d: Unable to register notifier for %s(0x%x)\n",
+ i, pd->domain_list->name,
+ pd->domain_list->instance_id);
+ ret = PTR_ERR(notifier[i].handle);
+ goto free_handle;
+ }
+ }
+
+ ar_snoc->service_notifier = notifier;
+ ar_snoc->total_domains = pd->total_domains;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "PD restart enabled\n");
+
+ return NOTIFY_OK;
+
+free_handle:
+ for (i = 0; i < pd->total_domains; i++) {
+ if (notifier[i].handle) {
+ service_notif_unregister_notifier(
+ notifier[i].handle,
+ &ar_snoc->service_notifier_nb);
+ }
+ }
+ kfree(notifier);
+
+out:
+ ath10k_err(ar, "PD restart not enabled: %d\n", ret);
+
+ return NOTIFY_OK;
+}
+
+int ath10k_snoc_pd_restart_enable(struct ath10k *ar)
+{
+ int ret;
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "Get service location\n");
+
+ ar_snoc->get_service_nb.notifier_call =
+ ath10k_snoc_get_service_location_notify;
+ ret = get_service_location(ATH10K_SERVICE_LOCATION_CLIENT_NAME,
+ ATH10K_WLAN_SERVICE_NAME,
+ &ar_snoc->get_service_nb);
+ if (ret) {
+ ath10k_err(ar, "Get service location failed: %d\n", ret);
+ goto out;
+ }
+
+ return 0;
+out:
+ ath10k_err(ar, "PD restart not enabled: %d\n", ret);
+ return ret;
+}
+
+int ath10k_snoc_pdr_unregister_notifier(struct ath10k *ar)
+{
+ int i;
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+
+ for (i = 0; i < ar_snoc->total_domains; i++) {
+ if (ar_snoc->service_notifier[i].handle)
+ service_notif_unregister_notifier(
+ ar_snoc->service_notifier[i].handle,
+ &ar_snoc->service_notifier_nb);
+ }
+
+ kfree(ar_snoc->service_notifier);
+
+ ar_snoc->service_notifier = NULL;
+
+ return 0;
+}
+
+static int ath10k_snoc_modem_notifier_nb(struct notifier_block *nb,
+ unsigned long code,
+ void *data)
+{
+ struct notif_data *notif = data;
+ struct ath10k_snoc *ar_snoc = container_of(nb, struct ath10k_snoc,
+ modem_ssr_nb);
+ struct ath10k *ar = ar_snoc->ar;
+
+ if (code != SUBSYS_BEFORE_SHUTDOWN)
+ return NOTIFY_OK;
+
+ if (notif->crashed)
+ atomic_set(&ar_snoc->fw_crashed, 1);
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "Modem went down %d\n",
+ atomic_read(&ar_snoc->fw_crashed));
+ if (notif->crashed)
+ queue_work(ar->workqueue, &ar->restart_work);
+
+ return NOTIFY_OK;
+}
+
+int ath10k_snoc_modem_ssr_register_notifier(struct ath10k *ar)
+{
+ int ret = 0;
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+
+ ar_snoc->modem_ssr_nb.notifier_call = ath10k_snoc_modem_notifier_nb;
+
+ ar_snoc->modem_notify_handler =
+ subsys_notif_register_notifier("modem", &ar_snoc->modem_ssr_nb);
+
+ if (IS_ERR(ar_snoc->modem_notify_handler)) {
+ ret = PTR_ERR(ar_snoc->modem_notify_handler);
+ ath10k_err(ar, "Modem register notifier failed: %d\n", ret);
+ }
+
+ return ret;
+}
+
+int ath10k_snoc_modem_ssr_unregister_notifier(struct ath10k *ar)
+{
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+
+ subsys_notif_unregister_notifier(ar_snoc->modem_notify_handler,
+ &ar_snoc->modem_ssr_nb);
+ ar_snoc->modem_notify_handler = NULL;
+
+ return 0;
+}
+
+static char *
+ath10k_snoc_driver_event_to_str(enum ath10k_snoc_driver_event_type type)
+{
+ switch (type) {
+ case ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE:
+ return "SERVER_ARRIVE";
+ case ATH10K_SNOC_DRIVER_EVENT_SERVER_EXIT:
+ return "SERVER_EXIT";
+ case ATH10K_SNOC_DRIVER_EVENT_FW_READY_IND:
+ return "FW_READY";
+ case ATH10K_SNOC_DRIVER_EVENT_MAX:
+ return "EVENT_MAX";
+ }
+
+ return "UNKNOWN";
+};
+
+static int
+ath10k_snoc_driver_event_post(enum ath10k_snoc_driver_event_type type,
+ u32 flags, void *data)
+{
+ int ret = 0;
+ int i = 0;
+ struct ath10k *ar = (struct ath10k *)data;
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "Posting event: %s type: %d\n",
+ ath10k_snoc_driver_event_to_str(type), type);
+
+ if (type >= ATH10K_SNOC_DRIVER_EVENT_MAX) {
+ ath10k_err(ar, "Invalid Event type: %d, can't post", type);
+ return -EINVAL;
+ }
+
+ spin_lock_bh(&qmi_cfg->event_lock);
+
+ for (i = 0; i < ATH10K_SNOC_DRIVER_EVENT_MAX; i++) {
+ if (atomic_read(&qmi_cfg->qmi_ev_list[i].event_handled)) {
+ qmi_cfg->qmi_ev_list[i].type = type;
+ qmi_cfg->qmi_ev_list[i].data = data;
+ init_completion(&qmi_cfg->qmi_ev_list[i].complete);
+ qmi_cfg->qmi_ev_list[i].ret =
+ ATH10K_SNOC_EVENT_PENDING;
+ qmi_cfg->qmi_ev_list[i].sync =
+ !!(flags & ATH10K_SNOC_EVENT_SYNC);
+ atomic_set(&qmi_cfg->qmi_ev_list[i].event_handled, 0);
+ list_add_tail(&qmi_cfg->qmi_ev_list[i].list,
+ &qmi_cfg->event_list);
+ break;
+ }
+ }
+
+ if (i >= ATH10K_SNOC_DRIVER_EVENT_MAX)
+ i = ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE;
+
+ spin_unlock_bh(&qmi_cfg->event_lock);
+
+ queue_work(qmi_cfg->event_wq, &qmi_cfg->event_work);
+
+ if (!(flags & ATH10K_SNOC_EVENT_SYNC))
+ goto out;
+
+ if (flags & ATH10K_SNOC_EVENT_UNINTERRUPTIBLE)
+ wait_for_completion(&qmi_cfg->qmi_ev_list[i].complete);
+ else
+ ret = wait_for_completion_interruptible(
+ &qmi_cfg->qmi_ev_list[i].complete);
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "Completed event: %s(%d)\n",
+ ath10k_snoc_driver_event_to_str(type), type);
+
+ spin_lock_bh(&qmi_cfg->event_lock);
+ if (ret == -ERESTARTSYS &&
+ qmi_cfg->qmi_ev_list[i].ret == ATH10K_SNOC_EVENT_PENDING) {
+ qmi_cfg->qmi_ev_list[i].sync = false;
+ atomic_set(&qmi_cfg->qmi_ev_list[i].event_handled, 1);
+ spin_unlock_bh(&qmi_cfg->event_lock);
+ ret = -EINTR;
+ goto out;
+ }
+ spin_unlock_bh(&qmi_cfg->event_lock);
+
+out:
+ return ret;
+}
+
+static int
+ath10k_snoc_wlan_mode_send_sync_msg(struct ath10k *ar,
+ enum wlfw_driver_mode_enum_v01 mode)
+{
+ int ret;
+ struct wlfw_wlan_mode_req_msg_v01 req;
+ struct wlfw_wlan_mode_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
+
+ if (!qmi_cfg || !qmi_cfg->wlfw_clnt)
+ return -ENODEV;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC,
+ "Sending Mode request, mode: %d\n", mode);
+
+ memset(&req, 0, sizeof(req));
+ memset(&resp, 0, sizeof(resp));
+
+ req.mode = mode;
+ req.hw_debug_valid = 1;
+ req.hw_debug = 0;
+
+ req_desc.max_msg_len = WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_WLAN_MODE_REQ_V01;
+ req_desc.ei_array = wlfw_wlan_mode_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_WLAN_MODE_RESP_V01;
+ resp_desc.ei_array = wlfw_wlan_mode_resp_msg_v01_ei;
+
+ ret = qmi_send_req_wait(qmi_cfg->wlfw_clnt,
+ &req_desc, &req, sizeof(req),
+ &resp_desc, &resp, sizeof(resp),
+ WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ ath10k_err(ar, "Send mode req failed, mode: %d ret: %d\n",
+ mode, ret);
+ return ret;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath10k_err(ar, "QMI mode request rejected:");
+ ath10k_err(ar, "mode:%d result:%d error:%d\n",
+ mode, resp.resp.result, resp.resp.error);
+ ret = resp.resp.result;
+ return ret;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC,
+ "wlan Mode request send success, mode: %d\n", mode);
+ return 0;
+}
+
+static int
+ath10k_snoc_wlan_cfg_send_sync_msg(struct ath10k *ar,
+ struct wlfw_wlan_cfg_req_msg_v01 *data)
+{
+ int ret;
+ struct wlfw_wlan_cfg_req_msg_v01 req;
+ struct wlfw_wlan_cfg_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
+
+ if (!qmi_cfg || !qmi_cfg->wlfw_clnt)
+ return -ENODEV;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "Sending config request\n");
+
+ memset(&req, 0, sizeof(req));
+ memset(&resp, 0, sizeof(resp));
+ memcpy(&req, data, sizeof(req));
+
+ req_desc.max_msg_len = WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_WLAN_CFG_REQ_V01;
+ req_desc.ei_array = wlfw_wlan_cfg_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_WLAN_CFG_RESP_V01;
+ resp_desc.ei_array = wlfw_wlan_cfg_resp_msg_v01_ei;
+
+ ret = qmi_send_req_wait(qmi_cfg->wlfw_clnt,
+ &req_desc, &req, sizeof(req),
+ &resp_desc, &resp, sizeof(resp),
+ WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ ath10k_err(ar, "Send config req failed %d\n", ret);
+ return ret;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath10k_err(ar, "QMI config request rejected:");
+ ath10k_err(ar, "result:%d error:%d\n",
+ resp.resp.result, resp.resp.error);
+ ret = resp.resp.result;
+ return ret;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "wlan config request success..\n");
+ return 0;
+}
+
+int ath10k_snoc_qmi_wlan_enable(struct ath10k *ar,
+ struct ath10k_wlan_enable_cfg *config,
+ enum ath10k_driver_mode mode,
+ const char *host_version)
+{
+ struct wlfw_wlan_cfg_req_msg_v01 req;
+ u32 i;
+ int ret;
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC,
+ "Mode: %d, config: %p, host_version: %s\n",
+ mode, config, host_version);
+
+ memset(&req, 0, sizeof(req));
+ if (!config || !host_version) {
+ ath10k_err(ar, "WLAN_EN Config Invalid:%p: host_version:%p\n",
+ config, host_version);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ wait_event_timeout(ath10k_fw_ready_wait_event,
+ (atomic_read(&qmi_cfg->fw_ready) &&
+ atomic_read(&qmi_cfg->server_connected)),
+ msecs_to_jiffies(ATH10K_SNOC_WLAN_FW_READY_TIMEOUT));
+
+ req.host_version_valid = 1;
+ strlcpy(req.host_version, host_version,
+ QMI_WLFW_MAX_STR_LEN_V01 + 1);
+
+ req.tgt_cfg_valid = 1;
+ if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01)
+ req.tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01;
+ else
+ req.tgt_cfg_len = config->num_ce_tgt_cfg;
+ for (i = 0; i < req.tgt_cfg_len; i++) {
+ req.tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num;
+ req.tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir;
+ req.tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries;
+ req.tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max;
+ req.tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags;
+ }
+
+ req.svc_cfg_valid = 1;
+ if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01)
+ req.svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01;
+ else
+ req.svc_cfg_len = config->num_ce_svc_pipe_cfg;
+ for (i = 0; i < req.svc_cfg_len; i++) {
+ req.svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id;
+ req.svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir;
+ req.svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num;
+ }
+
+ req.shadow_reg_valid = 1;
+ if (config->num_shadow_reg_cfg >
+ QMI_WLFW_MAX_NUM_SHADOW_REG_V01)
+ req.shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01;
+ else
+ req.shadow_reg_len = config->num_shadow_reg_cfg;
+
+ memcpy(req.shadow_reg, config->shadow_reg_cfg,
+ sizeof(struct wlfw_shadow_reg_cfg_s_v01) * req.shadow_reg_len);
+
+ ret = ath10k_snoc_wlan_cfg_send_sync_msg(ar, &req);
+ if (ret) {
+ ath10k_err(ar, "WLAN config send failed\n");
+ return ret;
+ }
+
+ ret = ath10k_snoc_wlan_mode_send_sync_msg(ar, mode);
+ if (ret) {
+ ath10k_err(ar, "WLAN mode send failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int ath10k_snoc_qmi_wlan_disable(struct ath10k *ar)
+{
+ return ath10k_snoc_wlan_mode_send_sync_msg(ar, QMI_WLFW_OFF_V01);
+}
+
+static int ath10k_snoc_ind_register_send_sync_msg(struct ath10k *ar)
+{
+ int ret;
+ struct wlfw_ind_register_req_msg_v01 req;
+ struct wlfw_ind_register_resp_msg_v01 resp;
+ struct msg_desc req_desc, resp_desc;
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC,
+ "Sending indication register message,\n");
+
+ memset(&req, 0, sizeof(req));
+ memset(&resp, 0, sizeof(resp));
+
+ req.client_id_valid = 1;
+ req.client_id = WLFW_CLIENT_ID;
+ req.fw_ready_enable_valid = 1;
+ req.fw_ready_enable = 1;
+ req.msa_ready_enable_valid = 1;
+ req.msa_ready_enable = 1;
+
+ req_desc.max_msg_len = WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN;
+ req_desc.msg_id = QMI_WLFW_IND_REGISTER_REQ_V01;
+ req_desc.ei_array = wlfw_ind_register_req_msg_v01_ei;
+
+ resp_desc.max_msg_len = WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN;
+ resp_desc.msg_id = QMI_WLFW_IND_REGISTER_RESP_V01;
+ resp_desc.ei_array = wlfw_ind_register_resp_msg_v01_ei;
+
+ ret = qmi_send_req_wait(qmi_cfg->wlfw_clnt,
+ &req_desc, &req, sizeof(req),
+ &resp_desc, &resp, sizeof(resp),
+ WLFW_TIMEOUT_MS);
+ if (ret < 0) {
+ ath10k_err(ar, "Send indication register req failed %d\n", ret);
+ return ret;
+ }
+
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ ath10k_err(ar, "QMI indication register request rejected:");
+ ath10k_err(ar, "resut:%d error:%d\n",
+ resp.resp.result, resp.resp.error);
+ ret = resp.resp.result;
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ath10k_snoc_qmi_wlfw_clnt_notify_work(struct work_struct *work)
+{
+ int ret;
+ struct ath10k_snoc_qmi_config *qmi_cfg =
+ container_of(work, struct ath10k_snoc_qmi_config,
+ qmi_recv_msg_work);
+ struct ath10k_snoc *ar_snoc =
+ container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg);
+ struct ath10k *ar = ar_snoc->ar;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC,
+ "Receiving Event in work queue context\n");
+
+ do {
+ } while ((ret = qmi_recv_msg(qmi_cfg->wlfw_clnt)) == 0);
+
+ if (ret != -ENOMSG)
+ ath10k_err(ar, "Error receiving message: %d\n", ret);
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "Receiving Event completed\n");
+}
+
+static void
+ath10k_snoc_qmi_wlfw_clnt_notify(struct qmi_handle *handle,
+ enum qmi_event_type event,
+ void *notify_priv)
+{
+ struct ath10k_snoc_qmi_config *qmi_cfg =
+ (struct ath10k_snoc_qmi_config *)notify_priv;
+ struct ath10k_snoc *ar_snoc =
+ container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg);
+ struct ath10k *ar = ar_snoc->ar;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "QMI client notify: %d\n", event);
+
+ if (!qmi_cfg || !qmi_cfg->wlfw_clnt)
+ return;
+
+ switch (event) {
+ case QMI_RECV_MSG:
+ schedule_work(&qmi_cfg->qmi_recv_msg_work);
+ break;
+ default:
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "Unknown Event: %d\n", event);
+ break;
+ }
+}
+
+static void
+ath10k_snoc_qmi_wlfw_clnt_ind(struct qmi_handle *handle,
+ unsigned int msg_id, void *msg,
+ unsigned int msg_len, void *ind_cb_priv)
+{
+ struct ath10k_snoc_qmi_config *qmi_cfg =
+ (struct ath10k_snoc_qmi_config *)ind_cb_priv;
+ struct ath10k_snoc *ar_snoc =
+ container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg);
+ struct ath10k *ar = ar_snoc->ar;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC,
+ "Received Ind 0x%x, msg_len: %d\n", msg_id, msg_len);
+ switch (msg_id) {
+ case QMI_WLFW_FW_READY_IND_V01:
+ ath10k_snoc_driver_event_post(
+ ATH10K_SNOC_DRIVER_EVENT_FW_READY_IND, 0, ar);
+ break;
+ case QMI_WLFW_MSA_READY_IND_V01:
+ qmi_cfg->msa_ready = true;
+ ath10k_dbg(ar, ATH10K_DBG_SNOC,
+ "Received MSA Ready, ind = 0x%x\n", msg_id);
+ break;
+ default:
+ ath10k_err(ar, "Invalid msg_id 0x%x\n", msg_id);
+ break;
+ }
+}
+
+static int ath10k_snoc_driver_event_server_arrive(struct ath10k *ar)
+{
+ int ret = 0;
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
+
+ if (!qmi_cfg)
+ return -ENODEV;
+
+ qmi_cfg->wlfw_clnt = qmi_handle_create(
+ ath10k_snoc_qmi_wlfw_clnt_notify, qmi_cfg);
+ if (!qmi_cfg->wlfw_clnt) {
+ ath10k_dbg(ar, ATH10K_DBG_SNOC,
+ "QMI client handle create failed\n");
+ return -ENOMEM;
+ }
+
+ ret = qmi_connect_to_service(qmi_cfg->wlfw_clnt,
+ WLFW_SERVICE_ID_V01,
+ WLFW_SERVICE_VERS_V01,
+ WLFW_SERVICE_INS_ID_V01);
+ if (ret < 0) {
+ ath10k_err(ar, "QMI WLAN Service not found : %d\n", ret);
+ goto err_qmi_config;
+ }
+
+ ret = qmi_register_ind_cb(qmi_cfg->wlfw_clnt,
+ ath10k_snoc_qmi_wlfw_clnt_ind, qmi_cfg);
+ if (ret < 0) {
+ ath10k_err(ar, "Failed to register indication callback: %d\n",
+ ret);
+ goto err_qmi_config;
+ }
+
+ ret = ath10k_snoc_ind_register_send_sync_msg(ar);
+ if (ret) {
+ ath10k_err(ar, "Failed to config qmi ind register\n");
+ goto err_qmi_config;
+ }
+
+ atomic_set(&qmi_cfg->server_connected, 1);
+ wake_up_all(&ath10k_fw_ready_wait_event);
+ ath10k_dbg(ar, ATH10K_DBG_SNOC,
+ "QMI Server Arrive Configuration Success\n");
+ return 0;
+
+err_qmi_config:
+ qmi_handle_destroy(qmi_cfg->wlfw_clnt);
+ qmi_cfg->wlfw_clnt = NULL;
+ return ret;
+}
+
+static int ath10k_snoc_driver_event_server_exit(struct ath10k *ar)
+{
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "QMI Server Exit event received\n");
+ atomic_set(&qmi_cfg->fw_ready, 0);
+ qmi_cfg->msa_ready = false;
+ atomic_set(&qmi_cfg->server_connected, 0);
+ return 0;
+}
+
+static int ath10k_snoc_driver_event_fw_ready_ind(struct ath10k *ar)
+{
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "FW Ready event received.\n");
+ atomic_set(&qmi_cfg->fw_ready, 1);
+ wake_up_all(&ath10k_fw_ready_wait_event);
+
+ return 0;
+}
+
+static void ath10k_snoc_driver_event_work(struct work_struct *work)
+{
+ struct ath10k_snoc_qmi_driver_event *event;
+ int ret;
+ struct ath10k_snoc_qmi_config *qmi_cfg =
+ container_of(work, struct ath10k_snoc_qmi_config, event_work);
+ struct ath10k_snoc *ar_snoc =
+ container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg);
+ struct ath10k *ar = ar_snoc->ar;
+
+ spin_lock_bh(&qmi_cfg->event_lock);
+
+ while (!list_empty(&qmi_cfg->event_list)) {
+ event = list_first_entry(&qmi_cfg->event_list,
+ struct ath10k_snoc_qmi_driver_event,
+ list);
+ list_del(&event->list);
+ spin_unlock_bh(&qmi_cfg->event_lock);
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "Processing event: %s%s(%d)\n",
+ ath10k_snoc_driver_event_to_str(event->type),
+ event->sync ? "-sync" : "", event->type);
+
+ switch (event->type) {
+ case ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE:
+ ret = ath10k_snoc_driver_event_server_arrive(ar);
+ break;
+ case ATH10K_SNOC_DRIVER_EVENT_SERVER_EXIT:
+ ret = ath10k_snoc_driver_event_server_exit(ar);
+ break;
+ case ATH10K_SNOC_DRIVER_EVENT_FW_READY_IND:
+ ret = ath10k_snoc_driver_event_fw_ready_ind(ar);
+ break;
+ default:
+ ath10k_err(ar, "Invalid Event type: %d", event->type);
+ kfree(event);
+ continue;
+ }
+
+ atomic_set(&event->event_handled, 1);
+ ath10k_dbg(ar, ATH10K_DBG_SNOC,
+ "Event Processed: %s%s(%d), ret: %d\n",
+ ath10k_snoc_driver_event_to_str(event->type),
+ event->sync ? "-sync" : "", event->type, ret);
+ spin_lock_bh(&qmi_cfg->event_lock);
+ if (event->sync) {
+ event->ret = ret;
+ complete(&event->complete);
+ continue;
+ }
+ spin_unlock_bh(&qmi_cfg->event_lock);
+ spin_lock_bh(&qmi_cfg->event_lock);
+ }
+
+ spin_unlock_bh(&qmi_cfg->event_lock);
+}
+
+static int
+ath10k_snoc_qmi_wlfw_clnt_svc_event_notify(struct notifier_block *this,
+ unsigned long code,
+ void *_cmd)
+{
+ int ret = 0;
+ struct ath10k_snoc_qmi_config *qmi_cfg =
+ container_of(this, struct ath10k_snoc_qmi_config, wlfw_clnt_nb);
+ struct ath10k_snoc *ar_snoc =
+ container_of(qmi_cfg, struct ath10k_snoc, qmi_cfg);
+ struct ath10k *ar = ar_snoc->ar;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "Event Notify: code: %ld", code);
+
+ switch (code) {
+ case QMI_SERVER_ARRIVE:
+ ret = ath10k_snoc_driver_event_post(
+ ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE, 0, ar);
+ break;
+ case QMI_SERVER_EXIT:
+ ret = ath10k_snoc_driver_event_post(
+ ATH10K_SNOC_DRIVER_EVENT_SERVER_EXIT, 0, ar);
+ break;
+ default:
+ ath10k_err(ar, "Invalid code: %ld", code);
+ break;
+ }
+
+ return ret;
+}
+
+int ath10k_snoc_start_qmi_service(struct ath10k *ar)
+{
+ int ret;
+ int i;
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
+
+ qmi_cfg->event_wq = alloc_workqueue("ath10k_snoc_driver_event",
+ WQ_UNBOUND, 1);
+ if (!qmi_cfg->event_wq) {
+ ath10k_err(ar, "Workqueue creation failed\n");
+ return -EFAULT;
+ }
+
+ spin_lock_init(&qmi_cfg->event_lock);
+ atomic_set(&qmi_cfg->fw_ready, 0);
+ atomic_set(&qmi_cfg->server_connected, 0);
+
+ INIT_WORK(&qmi_cfg->event_work, ath10k_snoc_driver_event_work);
+ INIT_WORK(&qmi_cfg->qmi_recv_msg_work,
+ ath10k_snoc_qmi_wlfw_clnt_notify_work);
+ INIT_LIST_HEAD(&qmi_cfg->event_list);
+
+ for (i = 0; i < ATH10K_SNOC_DRIVER_EVENT_MAX; i++)
+ atomic_set(&qmi_cfg->qmi_ev_list[i].event_handled, 1);
+
+ qmi_cfg->wlfw_clnt_nb.notifier_call =
+ ath10k_snoc_qmi_wlfw_clnt_svc_event_notify;
+ ret = qmi_svc_event_notifier_register(WLFW_SERVICE_ID_V01,
+ WLFW_SERVICE_VERS_V01,
+ WLFW_SERVICE_INS_ID_V01,
+ &qmi_cfg->wlfw_clnt_nb);
+ if (ret < 0) {
+ ath10k_err(ar, "Notifier register failed: %d\n", ret);
+ ret = -EFAULT;
+ goto out_destroy_wq;
+ }
+
+ atomic_set(&qmi_cfg->fw_ready, 1);
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "QMI service started successfully\n");
+ return 0;
+
+out_destroy_wq:
+ destroy_workqueue(qmi_cfg->event_wq);
+ return ret;
+}
+
+void ath10k_snoc_stop_qmi_service(struct ath10k *ar)
+{
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ struct ath10k_snoc_qmi_config *qmi_cfg = &ar_snoc->qmi_cfg;
+
+ ath10k_dbg(ar, ATH10K_DBG_SNOC, "Removing QMI service..\n");
+
+ qmi_svc_event_notifier_unregister(WLFW_SERVICE_ID_V01,
+ WLFW_SERVICE_VERS_V01,
+ WLFW_SERVICE_INS_ID_V01,
+ &qmi_cfg->wlfw_clnt_nb);
+
+ wake_up_all(&ath10k_fw_ready_wait_event);
+ destroy_workqueue(qmi_cfg->event_wq);
+ qmi_cfg = NULL;
+}
diff --git a/drivers/net/wireless/ath/ath10k/qmi.h b/drivers/net/wireless/ath/ath10k/qmi.h
new file mode 100644
index 000000000000..c8bc26bb96b2
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/qmi.h
@@ -0,0 +1,156 @@
+/* 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 _QMI_H_
+#define _QMI_H_
+
+#define ATH10K_SNOC_EVENT_PENDING 2989
+#define ATH10K_SNOC_EVENT_SYNC BIT(0)
+#define ATH10K_SNOC_EVENT_UNINTERRUPTIBLE BIT(1)
+#define ATH10K_SNOC_WLAN_FW_READY_TIMEOUT 8000
+
+#define WLFW_SERVICE_INS_ID_V01 0
+#define WLFW_CLIENT_ID 0x4b4e454c
+#define WLFW_TIMEOUT_MS 20000
+
+enum ath10k_snoc_driver_event_type {
+ ATH10K_SNOC_DRIVER_EVENT_SERVER_ARRIVE,
+ ATH10K_SNOC_DRIVER_EVENT_SERVER_EXIT,
+ ATH10K_SNOC_DRIVER_EVENT_FW_READY_IND,
+ ATH10K_SNOC_DRIVER_EVENT_MAX,
+};
+
+/* enum ath10k_driver_mode: ath10k driver mode
+ * @ATH10K_MISSION: mission mode
+ * @ATH10K_FTM: ftm mode
+ * @ATH10K_EPPING: epping mode
+ * @ATH10K_OFF: off mode
+ */
+enum ath10k_driver_mode {
+ ATH10K_MISSION,
+ ATH10K_FTM,
+ ATH10K_EPPING,
+ ATH10K_OFF
+};
+
+/* struct ath10k_ce_tgt_pipe_cfg: target pipe configuration
+ * @pipe_num: pipe number
+ * @pipe_dir: pipe direction
+ * @nentries: entries in pipe
+ * @nbytes_max: pipe max size
+ * @flags: pipe flags
+ * @reserved: reserved
+ */
+struct ath10k_ce_tgt_pipe_cfg {
+ u32 pipe_num;
+ u32 pipe_dir;
+ u32 nentries;
+ u32 nbytes_max;
+ u32 flags;
+ u32 reserved;
+};
+
+/* struct ath10k_ce_svc_pipe_cfg: service pipe configuration
+ * @service_id: target version
+ * @pipe_dir: pipe direction
+ * @pipe_num: pipe number
+ */
+struct ath10k_ce_svc_pipe_cfg {
+ u32 service_id;
+ u32 pipe_dir;
+ u32 pipe_num;
+};
+
+/* struct ath10k_shadow_reg_cfg: shadow register configuration
+ * @ce_id: copy engine id
+ * @reg_offset: offset to copy engine
+ */
+struct ath10k_shadow_reg_cfg {
+ u16 ce_id;
+ u16 reg_offset;
+};
+
+/* struct ath10k_wlan_enable_cfg: wlan enable configuration
+ * @num_ce_tgt_cfg: no of ce target configuration
+ * @ce_tgt_cfg: target ce configuration
+ * @num_ce_svc_pipe_cfg: no of ce service configuration
+ * @ce_svc_cfg: ce service configuration
+ * @num_shadow_reg_cfg: no of shadow registers
+ * @shadow_reg_cfg: shadow register configuration
+ */
+struct ath10k_wlan_enable_cfg {
+ u32 num_ce_tgt_cfg;
+ struct ath10k_ce_tgt_pipe_cfg *ce_tgt_cfg;
+ u32 num_ce_svc_pipe_cfg;
+ struct ath10k_ce_svc_pipe_cfg *ce_svc_cfg;
+ u32 num_shadow_reg_cfg;
+ struct ath10k_shadow_reg_cfg *shadow_reg_cfg;
+};
+
+/* struct ath10k_snoc_qmi_driver_event: qmi driver event
+ * event_handled: event handled by event work handler
+ * sync: event synced
+ * ret: event received return value
+ * list: list to queue qmi event for process
+ * type: driver event type
+ * complete: completion for event handle complete
+ * data: encapsulate driver data for event handler callback
+ */
+struct ath10k_snoc_qmi_driver_event {
+ atomic_t event_handled;
+ bool sync;
+ int ret;
+ struct list_head list;
+ enum ath10k_snoc_driver_event_type type;
+ struct completion complete;
+ void *data;
+};
+
+/* struct ath10k_snoc_qmi_config: qmi service configuration
+ * fw_ready: wlan firmware ready for wlan operation
+ * msa_ready: wlan firmware msa memory ready for board data download
+ * server_connected: qmi server connected
+ * event_work: QMI event work
+ * event_list: QMI event list
+ * qmi_recv_msg_work: QMI message receive work
+ * event_wq: QMI event work queue
+ * wlfw_clnt_nb: WLAN firmware indication callback
+ * wlfw_clnt: QMI notifier handler for wlan firmware
+ * qmi_ev_list: QMI event list
+ * event_lock: spinlock for qmi event work queue
+ */
+struct ath10k_snoc_qmi_config {
+ atomic_t fw_ready;
+ bool msa_ready;
+ atomic_t server_connected;
+ struct work_struct event_work;
+ struct list_head event_list;
+ struct work_struct qmi_recv_msg_work;
+ struct workqueue_struct *event_wq;
+ struct notifier_block wlfw_clnt_nb;
+ struct qmi_handle *wlfw_clnt;
+ struct ath10k_snoc_qmi_driver_event
+ qmi_ev_list[ATH10K_SNOC_DRIVER_EVENT_MAX];
+ spinlock_t event_lock; /* spinlock for qmi event work queue */
+};
+
+int ath10k_snoc_pd_restart_enable(struct ath10k *ar);
+int ath10k_snoc_modem_ssr_register_notifier(struct ath10k *ar);
+int ath10k_snoc_modem_ssr_unregister_notifier(struct ath10k *ar);
+int ath10k_snoc_pdr_unregister_notifier(struct ath10k *ar);
+int ath10k_snoc_start_qmi_service(struct ath10k *ar);
+void ath10k_snoc_stop_qmi_service(struct ath10k *ar);
+int ath10k_snoc_qmi_wlan_enable(struct ath10k *ar,
+ struct ath10k_wlan_enable_cfg *config,
+ enum ath10k_driver_mode mode,
+ const char *host_version);
+int ath10k_snoc_qmi_wlan_disable(struct ath10k *ar);
+#endif
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index dc5f6fdaa9dc..add0a7cd9edb 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -17,17 +17,18 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/bitops.h>
-
#include "core.h"
#include "debug.h"
#include "hif.h"
#include "htc.h"
#include "ce.h"
#include "snoc.h"
-#include <soc/qcom/icnss.h>
+#include "qmi.h"
#include <linux/of.h>
#include <linux/platform_device.h>
+
#define WCN3990_MAX_IRQ 12
+
const char *ce_name[WCN3990_MAX_IRQ] = {
"WLAN_CE_0",
"WLAN_CE_1",
@@ -413,6 +414,20 @@ static struct ath10k_shadow_reg_cfg target_shadow_reg_cfg_map[] = {
{ 11, WCN3990_DST_WR_INDEX_OFFSET},
};
+static bool ath10k_snoc_has_fw_crashed(struct ath10k *ar)
+{
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+
+ return atomic_read(&ar_snoc->fw_crashed);
+}
+
+static void ath10k_snoc_fw_crashed_clear(struct ath10k *ar)
+{
+ struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+
+ atomic_set(&ar_snoc->fw_crashed, 0);
+}
+
void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value)
{
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
@@ -655,6 +670,9 @@ static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
"snoc tx item %d paddr %pad len %d n_items %d\n",
i, &items[i].paddr, items[i].len, n_items);
+ if (ath10k_snoc_has_fw_crashed(ar))
+ return -EINVAL;
+
err = ath10k_ce_send_nolock(ce_pipe,
items[i].transfer_context,
items[i].paddr,
@@ -867,11 +885,17 @@ static void ath10k_snoc_hif_stop(struct ath10k *ar)
{
if (!ar)
return;
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
- ath10k_snoc_irq_disable(ar);
+ if (ath10k_snoc_has_fw_crashed(ar) ||
+ test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
+ ath10k_snoc_free_irq(ar);
+ } else {
+ ath10k_snoc_irq_disable(ar);
+ }
+
ath10k_snoc_flush(ar);
napi_synchronize(&ar->napi);
napi_disable(&ar->napi);
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");
}
static int ath10k_snoc_alloc_pipes(struct ath10k *ar)
@@ -933,7 +957,7 @@ static void ath10k_snoc_hif_power_down(struct ath10k *ar)
{
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");
msleep(SNOC_HIF_POWER_DOWN_DELAY);
- icnss_wlan_disable(ICNSS_OFF);
+ ath10k_snoc_qmi_wlan_disable(ar);
}
int ath10k_snoc_get_ce_id(struct ath10k *ar, int irq)
@@ -1037,7 +1061,7 @@ static int ath10k_snoc_get_soc_info(struct ath10k *ar)
static int ath10k_snoc_wlan_enable(struct ath10k *ar)
{
- struct icnss_wlan_enable_cfg cfg;
+ struct ath10k_wlan_enable_cfg cfg;
int pipe_num;
struct ath10k_ce_tgt_pipe_cfg tgt_cfg[CE_COUNT_MAX];
@@ -1056,19 +1080,20 @@ static int ath10k_snoc_wlan_enable(struct ath10k *ar)
}
cfg.num_ce_tgt_cfg = sizeof(target_ce_config_wlan) /
- sizeof(struct ce_tgt_pipe_cfg);
- cfg.ce_tgt_cfg = (struct ce_tgt_pipe_cfg *)
+ sizeof(struct ath10k_ce_tgt_pipe_cfg);
+ cfg.ce_tgt_cfg = (struct ath10k_ce_tgt_pipe_cfg *)
&tgt_cfg;
cfg.num_ce_svc_pipe_cfg = sizeof(target_service_to_ce_map_wlan) /
- sizeof(struct ce_svc_pipe_cfg);
- cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *)
+ sizeof(struct ath10k_ce_svc_pipe_cfg);
+ cfg.ce_svc_cfg = (struct ath10k_ce_svc_pipe_cfg *)
&target_service_to_ce_map_wlan;
cfg.num_shadow_reg_cfg = sizeof(target_shadow_reg_cfg_map) /
- sizeof(struct icnss_shadow_reg_cfg);
- cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *)
+ sizeof(struct ath10k_shadow_reg_cfg);
+ cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *)
&target_shadow_reg_cfg_map;
- return icnss_wlan_enable(&cfg, ICNSS_MISSION, "5.1.0.26N");
+ return ath10k_snoc_qmi_wlan_enable(ar, &cfg,
+ ATH10K_MISSION, "5.1.0.26N");
}
static int ath10k_snoc_bus_configure(struct ath10k *ar)
@@ -1087,9 +1112,14 @@ static int ath10k_snoc_bus_configure(struct ath10k *ar)
static int ath10k_snoc_hif_start(struct ath10k *ar)
{
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
+ if (ath10k_snoc_has_fw_crashed(ar)) {
+ ath10k_snoc_request_irq(ar);
+ ath10k_snoc_fw_crashed_clear(ar);
+ }
ath10k_snoc_irq_enable(ar);
ath10k_snoc_rx_post(ar);
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");
return 0;
}
@@ -1110,7 +1140,8 @@ static int ath10k_snoc_hif_power_up(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 driver state = %d\n",
__func__, ar->state);
- if (ar->state == ATH10K_STATE_ON) {
+ if (ar->state == ATH10K_STATE_ON ||
+ test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
ret = ath10k_snoc_bus_configure(ar);
if (ret)
ath10k_err(ar, "failed to configure bus: %d\n", ret);
@@ -1133,6 +1164,10 @@ static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget)
struct ath10k *ar = container_of(ctx, struct ath10k, napi);
int done = 0;
+ if (ath10k_snoc_has_fw_crashed(ar)) {
+ napi_complete(ctx);
+ return done;
+ }
ath10k_ce_per_engine_service_any(ar);
done = ath10k_htt_txrx_compl_task(ar, budget);
@@ -1211,6 +1246,12 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ar);
ar_snoc->ar = ar;
+ ret = ath10k_snoc_start_qmi_service(ar);
+ if (ret) {
+ ath10k_err(ar, "failed to start QMI service: %d\n", ret);
+ goto err_core_destroy;
+ }
+
spin_lock_init(&ar_snoc->opaque_ctx.ce_lock);
ar_snoc->opaque_ctx.bus_ops = &ath10k_snoc_bus_ops;
ath10k_snoc_resource_init(ar);
@@ -1254,6 +1295,10 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
ath10k_err(ar, "failed to register driver core: %d\n", ret);
goto err_free_irq;
}
+
+ ath10k_snoc_modem_ssr_register_notifier(ar);
+ ath10k_snoc_pd_restart_enable(ar);
+
ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 probed\n", __func__);
return 0;
@@ -1282,9 +1327,12 @@ static int ath10k_snoc_remove(struct platform_device *pdev)
return -EINVAL;
ath10k_core_unregister(ar);
+ ath10k_snoc_pdr_unregister_notifier(ar);
+ ath10k_snoc_modem_ssr_unregister_notifier(ar);
ath10k_snoc_free_irq(ar);
ath10k_snoc_release_resource(ar);
ath10k_snoc_free_pipes(ar);
+ ath10k_snoc_stop_qmi_service(ar);
ath10k_core_destroy(ar);
ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 removed\n", __func__);
@@ -1312,10 +1360,6 @@ static int __init ath10k_snoc_init(void)
{
int ret;
- if (!icnss_is_fw_ready()) {
- pr_err("failed to get fw ready indication\n");
- return -EAGAIN;
- }
ret = platform_driver_register(&ath10k_snoc_driver);
if (ret)
pr_err("failed to register ath10k snoc driver: %d\n",
diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h
index 0a5f5bff37ec..99ae157885bb 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.h
+++ b/drivers/net/wireless/ath/ath10k/snoc.h
@@ -16,8 +16,12 @@
#include "hw.h"
#include "ce.h"
#include "pci.h"
+#include "qmi.h"
+#include <soc/qcom/service-locator.h>
#define ATH10K_SNOC_RX_POST_RETRY_MS 50
#define CE_POLL_PIPE 4
+#define ATH10K_SERVICE_LOCATION_CLIENT_NAME "ATH10K-WLAN"
+#define ATH10K_WLAN_SERVICE_NAME "wlan/fw"
/* struct snoc_state: SNOC target state
* @pipe_cfg_addr: pipe configuration address
@@ -88,6 +92,17 @@ struct ath10k_target_info {
u32 soc_version;
};
+/* struct ath10k_service_notifier_context: service notification context
+ * @handle: notifier handle
+ * @instance_id: domain instance id
+ * @name: domain name
+ */
+struct ath10k_service_notifier_context {
+ void *handle;
+ u32 instance_id;
+ char name[QMI_SERVREG_LOC_NAME_LENGTH_V01 + 1];
+};
+
/* struct ath10k_snoc: SNOC info struct
* @dev: device structure
* @ar:ath10k base structure
@@ -101,6 +116,13 @@ struct ath10k_target_info {
* @rx_post_retry: rx buffer post processing timer
* @vaddr_rri_on_ddr: virtual address for RRI
* @is_driver_probed: flag to indicate driver state
+ * @modem_ssr_nb: notifier callback for modem notification
+ * @modem_notify_handler: modem notification handler
+ * @service_notifier: notifier context for service notification
+ * @service_notifier_nb: notifier callback for service notification
+ * @total_domains: no of service domains
+ * @get_service_nb: notifier callback for service discovery
+ * @fw_crashed: fw state flag
*/
struct ath10k_snoc {
struct bus_opaque opaque_ctx;
@@ -115,73 +137,19 @@ struct ath10k_snoc {
u32 ce_irqs[CE_COUNT_MAX];
u32 *vaddr_rri_on_ddr;
bool is_driver_probed;
+ struct notifier_block modem_ssr_nb;
+ void *modem_notify_handler;
+ struct ath10k_service_notifier_context *service_notifier;
+ struct notifier_block service_notifier_nb;
+ int total_domains;
+ struct notifier_block get_service_nb;
+ atomic_t fw_crashed;
+ struct ath10k_snoc_qmi_config qmi_cfg;
};
-/* struct ath10k_ce_tgt_pipe_cfg: target pipe configuration
- * @pipe_num: pipe number
- * @pipe_dir: pipe direction
- * @nentries: entries in pipe
- * @nbytes_max: pipe max size
- * @flags: pipe flags
- * @reserved: reserved
- */
-struct ath10k_ce_tgt_pipe_cfg {
- u32 pipe_num;
- u32 pipe_dir;
- u32 nentries;
- u32 nbytes_max;
- u32 flags;
- u32 reserved;
-};
-
-/* struct ath10k_ce_svc_pipe_cfg: service pipe configuration
- * @service_id: target version
- * @pipe_dir: pipe direction
- * @pipe_num: pipe number
- */
-struct ath10k_ce_svc_pipe_cfg {
- u32 service_id;
- u32 pipe_dir;
- u32 pipe_num;
-};
-
-/* struct ath10k_shadow_reg_cfg: shadow register configuration
- * @ce_id: copy engine id
- * @reg_offset: offset to copy engine
- */
-struct ath10k_shadow_reg_cfg {
- u16 ce_id;
- u16 reg_offset;
-};
-
-/* struct ath10k_wlan_enable_cfg: wlan enable configuration
- * @num_ce_tgt_cfg: no of ce target configuration
- * @ce_tgt_cfg: target ce configuration
- * @num_ce_svc_pipe_cfg: no of ce service configuration
- * @ce_svc_cfg: ce service configuration
- * @num_shadow_reg_cfg: no of shadow registers
- * @shadow_reg_cfg: shadow register configuration
- */
-struct ath10k_wlan_enable_cfg {
- u32 num_ce_tgt_cfg;
- struct ath10k_ce_tgt_pipe_cfg *ce_tgt_cfg;
- u32 num_ce_svc_pipe_cfg;
- struct ath10k_ce_svc_pipe_cfg *ce_svc_cfg;
- u32 num_shadow_reg_cfg;
- struct ath10k_shadow_reg_cfg *shadow_reg_cfg;
-};
-
-/* enum ath10k_driver_mode: ath10k driver mode
- * @ATH10K_MISSION: mission mode
- * @ATH10K_FTM: ftm mode
- * @ATH10K_EPPING: epping mode
- * @ATH10K_OFF: off mode
- */
-enum ath10k_driver_mode {
- ATH10K_MISSION,
- ATH10K_FTM,
- ATH10K_EPPING,
- ATH10K_OFF
+struct ath10k_event_pd_down_data {
+ bool crashed;
+ bool fw_rejuvenate;
};
static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
diff --git a/drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.c b/drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.c
new file mode 100644
index 000000000000..7d6cf8b23814
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.c
@@ -0,0 +1,2091 @@
+ /* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/qmi_encdec.h>
+
+#include <soc/qcom/msm_qmi_interface.h>
+
+#include "wcn3990_qmi_service_v01.h"
+
+static struct elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ pipe_num),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_pipedir_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ pipe_dir),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ nentries),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ nbytes_max),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_tgt_pipe_cfg_s_v01,
+ flags),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_ce_svc_pipe_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01,
+ service_id),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_pipedir_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01,
+ pipe_dir),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_ce_svc_pipe_cfg_s_v01,
+ pipe_num),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_shadow_reg_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint16_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01,
+ id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint16_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_shadow_reg_cfg_s_v01,
+ offset),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_shadow_reg_v2_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_shadow_reg_v2_cfg_s_v01,
+ addr),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_memory_region_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint64_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_memory_region_info_s_v01,
+ region_addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_memory_region_info_s_v01,
+ size),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_memory_region_info_s_v01,
+ secure_flag),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_rf_chip_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_rf_chip_info_s_v01,
+ chip_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_rf_chip_info_s_v01,
+ chip_family),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_rf_board_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_rf_board_info_s_v01,
+ board_id),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_soc_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_soc_info_s_v01,
+ soc_id),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_fw_version_info_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_fw_version_info_s_v01,
+ fw_version),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1,
+ .elem_size = sizeof(char),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_fw_version_info_s_v01,
+ fw_build_timestamp),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_ind_register_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ fw_ready_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ fw_ready_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ initiate_cal_download_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ initiate_cal_download_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ initiate_cal_update_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ initiate_cal_update_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ msa_ready_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ msa_ready_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ pin_connect_result_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ pin_connect_result_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ client_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ client_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x16,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ request_mem_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x16,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ request_mem_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x17,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ fw_mem_ready_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x17,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ fw_mem_ready_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x18,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ cold_boot_cal_done_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x18,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ cold_boot_cal_done_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x19,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ rejuvenate_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x19,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ rejuvenate_enable),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_ind_register_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct wlfw_ind_register_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_ind_register_resp_msg_v01,
+ fw_status_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint64_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_ind_register_resp_msg_v01,
+ fw_status),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_fw_ready_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_msa_ready_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_pin_connect_result_ind_msg_v01,
+ pwr_pin_result_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_pin_connect_result_ind_msg_v01,
+ pwr_pin_result),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(
+ struct wlfw_pin_connect_result_ind_msg_v01,
+ phy_io_pin_result_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(
+ struct wlfw_pin_connect_result_ind_msg_v01,
+ phy_io_pin_result),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(
+ struct wlfw_pin_connect_result_ind_msg_v01,
+ rf_pin_result_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(
+ struct wlfw_pin_connect_result_ind_msg_v01,
+ rf_pin_result),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_wlan_mode_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_driver_mode_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01,
+ mode),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01,
+ hw_debug_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_wlan_mode_req_msg_v01,
+ hw_debug),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_wlan_mode_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_wlan_mode_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ host_version_valid),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_WLFW_MAX_STR_LEN_V01 + 1,
+ .elem_size = sizeof(char),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ host_version),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ tgt_cfg_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ tgt_cfg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_CE_V01,
+ .elem_size = sizeof(struct wlfw_ce_tgt_pipe_cfg_s_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ tgt_cfg),
+ .ei_array = wlfw_ce_tgt_pipe_cfg_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ svc_cfg_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ svc_cfg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_SVC_V01,
+ .elem_size = sizeof(struct wlfw_ce_svc_pipe_cfg_s_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ svc_cfg),
+ .ei_array = wlfw_ce_svc_pipe_cfg_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01,
+ .elem_size = sizeof(struct wlfw_shadow_reg_cfg_s_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg),
+ .ei_array = wlfw_shadow_reg_cfg_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_v2_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_v2_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01,
+ .elem_size = sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_wlan_cfg_req_msg_v01,
+ shadow_reg_v2),
+ .ei_array = wlfw_shadow_reg_v2_cfg_s_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_wlan_cfg_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_wlan_cfg_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cap_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cap_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ chip_info_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct wlfw_rf_chip_info_s_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ chip_info),
+ .ei_array = wlfw_rf_chip_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ board_info_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct wlfw_rf_board_info_s_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ board_info),
+ .ei_array = wlfw_rf_board_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ soc_info_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct wlfw_soc_info_s_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ soc_info),
+ .ei_array = wlfw_soc_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ fw_version_info_valid),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct wlfw_fw_version_info_s_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ fw_version_info),
+ .ei_array = wlfw_fw_version_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ fw_build_id_valid),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1,
+ .elem_size = sizeof(char),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cap_resp_msg_v01,
+ fw_build_id),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_bdf_download_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ valid),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ file_id_valid),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ file_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ total_size_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ total_size),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ seg_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ seg_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint16_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
+ .elem_size = sizeof(uint8_t),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ end_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_bdf_download_req_msg_v01,
+ end),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_bdf_download_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct wlfw_bdf_download_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cal_report_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_cal_report_req_msg_v01,
+ meta_data_len),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = QMI_WLFW_MAX_NUM_CAL_V01,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_cal_report_req_msg_v01,
+ meta_data),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cal_report_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_cal_report_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(
+ struct wlfw_initiate_cal_download_ind_msg_v01,
+ cal_id),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cal_download_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ valid),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ file_id_valid),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ file_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ total_size_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ total_size),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ seg_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ seg_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint16_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
+ .elem_size = sizeof(uint8_t),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ end_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cal_download_req_msg_v01,
+ end),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cal_download_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct wlfw_cal_download_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(
+ struct wlfw_initiate_cal_update_ind_msg_v01,
+ cal_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct wlfw_initiate_cal_update_ind_msg_v01,
+ total_size),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cal_update_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_cal_update_req_msg_v01,
+ cal_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_cal_update_req_msg_v01,
+ seg_id),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cal_update_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ file_id_valid),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_cal_temp_id_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ file_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ total_size_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ total_size),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ seg_id_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ seg_id),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint16_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
+ .elem_size = sizeof(uint8_t),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ end_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_cal_update_resp_msg_v01,
+ end),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_msa_info_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint64_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_msa_info_req_msg_v01,
+ msa_addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_msa_info_req_msg_v01,
+ size),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_msa_info_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_msa_info_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct wlfw_msa_info_resp_msg_v01,
+ mem_region_info_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01,
+ .elem_size = sizeof(struct wlfw_memory_region_info_s_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct wlfw_msa_info_resp_msg_v01,
+ mem_region_info),
+ .ei_array = wlfw_memory_region_info_s_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_msa_ready_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_msa_ready_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_msa_ready_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_ini_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ini_req_msg_v01,
+ enablefwlog_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_ini_req_msg_v01,
+ enablefwlog),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_ini_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_ini_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_athdiag_read_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+ offset),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+ mem_type),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct wlfw_athdiag_read_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_athdiag_read_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct wlfw_athdiag_read_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_athdiag_read_resp_msg_v01,
+ data_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint16_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_athdiag_read_resp_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
+ .elem_size = sizeof(uint8_t),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_athdiag_read_resp_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_athdiag_write_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(
+ struct wlfw_athdiag_write_req_msg_v01,
+ offset),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct wlfw_athdiag_write_req_msg_v01,
+ mem_type),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(uint16_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(
+ struct wlfw_athdiag_write_req_msg_v01,
+ data_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAX_DATA_SIZE_V01,
+ .elem_size = sizeof(uint8_t),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(
+ struct wlfw_athdiag_write_req_msg_v01,
+ data),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_athdiag_write_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct wlfw_athdiag_write_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_vbatt_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint64_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_vbatt_req_msg_v01,
+ voltage_uv),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_vbatt_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_vbatt_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_mac_addr_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_mac_addr_req_msg_v01,
+ mac_addr_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = QMI_WLFW_MAC_ADDR_SIZE_V01,
+ .elem_size = sizeof(uint8_t),
+ .is_array = STATIC_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_mac_addr_req_msg_v01,
+ mac_addr),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_mac_addr_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_mac_addr_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_host_cap_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ daemon_support_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ daemon_support),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_host_cap_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_host_cap_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_request_mem_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_request_mem_ind_msg_v01,
+ size),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_respond_mem_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint64_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_respond_mem_req_msg_v01,
+ addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_respond_mem_req_msg_v01,
+ size),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_respond_mem_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct wlfw_respond_mem_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ cause_for_rejuvenation_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ cause_for_rejuvenation),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ requesting_sub_system_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ requesting_sub_system),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ line_number_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint16_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ line_number),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ function_name_valid),
+ },
+ {
+ .data_type = QMI_STRING,
+ .elem_len = QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1,
+ .elem_size = sizeof(char),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_rejuvenate_ind_msg_v01,
+ function_name),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct wlfw_rejuvenate_ack_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct
+ wlfw_dynamic_feature_mask_req_msg_v01,
+ mask_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint64_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_dynamic_feature_mask_req_msg_v01,
+ mask),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ resp),
+ .ei_array = get_qmi_response_type_v01_ei(),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ prev_mask_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint64_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(
+ struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ prev_mask),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(
+ struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ curr_mask_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint64_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x11,
+ .offset = offsetof(
+ struct wlfw_dynamic_feature_mask_resp_msg_v01,
+ curr_mask),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
diff --git a/drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.h b/drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.h
new file mode 100644
index 000000000000..21513b8f6200
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/wcn3990_qmi_service_v01.h
@@ -0,0 +1,619 @@
+ /* 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 WLAN_FIRMWARE_SERVICE_V01_H
+#define WLAN_FIRMWARE_SERVICE_V01_H
+
+#define WLFW_SERVICE_ID_V01 0x45
+#define WLFW_SERVICE_VERS_V01 0x01
+
+#define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025
+#define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037
+#define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A
+#define QMI_WLFW_HOST_CAP_REQ_V01 0x0034
+#define QMI_WLFW_DYNAMIC_FEATURE_MASK_RESP_V01 0x003B
+#define QMI_WLFW_CAP_REQ_V01 0x0024
+#define QMI_WLFW_CAL_REPORT_REQ_V01 0x0026
+#define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029
+#define QMI_WLFW_CAL_DOWNLOAD_RESP_V01 0x0027
+#define QMI_WLFW_INI_RESP_V01 0x002F
+#define QMI_WLFW_CAL_REPORT_RESP_V01 0x0026
+#define QMI_WLFW_MAC_ADDR_RESP_V01 0x0033
+#define QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01 0x0028
+#define QMI_WLFW_HOST_CAP_RESP_V01 0x0034
+#define QMI_WLFW_MSA_READY_IND_V01 0x002B
+#define QMI_WLFW_ATHDIAG_WRITE_RESP_V01 0x0031
+#define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022
+#define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020
+#define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023
+#define QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01 0x0038
+#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035
+#define QMI_WLFW_REJUVENATE_IND_V01 0x0039
+#define QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01 0x003B
+#define QMI_WLFW_ATHDIAG_WRITE_REQ_V01 0x0031
+#define QMI_WLFW_WLAN_MODE_RESP_V01 0x0022
+#define QMI_WLFW_RESPOND_MEM_REQ_V01 0x0036
+#define QMI_WLFW_PIN_CONNECT_RESULT_IND_V01 0x002C
+#define QMI_WLFW_FW_READY_IND_V01 0x0021
+#define QMI_WLFW_MSA_READY_RESP_V01 0x002E
+#define QMI_WLFW_CAL_UPDATE_REQ_V01 0x0029
+#define QMI_WLFW_INI_REQ_V01 0x002F
+#define QMI_WLFW_BDF_DOWNLOAD_RESP_V01 0x0025
+#define QMI_WLFW_REJUVENATE_ACK_RESP_V01 0x003A
+#define QMI_WLFW_MSA_INFO_RESP_V01 0x002D
+#define QMI_WLFW_MSA_READY_REQ_V01 0x002E
+#define QMI_WLFW_CAP_RESP_V01 0x0024
+#define QMI_WLFW_REJUVENATE_ACK_REQ_V01 0x003A
+#define QMI_WLFW_ATHDIAG_READ_RESP_V01 0x0030
+#define QMI_WLFW_VBATT_REQ_V01 0x0032
+#define QMI_WLFW_MAC_ADDR_REQ_V01 0x0033
+#define QMI_WLFW_RESPOND_MEM_RESP_V01 0x0036
+#define QMI_WLFW_VBATT_RESP_V01 0x0032
+#define QMI_WLFW_MSA_INFO_REQ_V01 0x002D
+#define QMI_WLFW_CAL_DOWNLOAD_REQ_V01 0x0027
+#define QMI_WLFW_ATHDIAG_READ_REQ_V01 0x0030
+#define QMI_WLFW_WLAN_CFG_REQ_V01 0x0023
+#define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020
+
+#define QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01 2
+#define QMI_WLFW_MAX_NUM_CAL_V01 5
+#define QMI_WLFW_MAX_DATA_SIZE_V01 6144
+#define QMI_WLFW_FUNCTION_NAME_LEN_V01 128
+#define QMI_WLFW_MAX_NUM_CE_V01 12
+#define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32
+#define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128
+#define QMI_WLFW_MAX_STR_LEN_V01 16
+#define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24
+#define QMI_WLFW_MAC_ADDR_SIZE_V01 6
+#define QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01 36
+#define QMI_WLFW_MAX_NUM_SVC_V01 24
+
+enum wlfw_driver_mode_enum_v01 {
+ WLFW_DRIVER_MODE_ENUM_MIN_VAL_V01 = INT_MIN,
+ QMI_WLFW_MISSION_V01 = 0,
+ QMI_WLFW_FTM_V01 = 1,
+ QMI_WLFW_EPPING_V01 = 2,
+ QMI_WLFW_WALTEST_V01 = 3,
+ QMI_WLFW_OFF_V01 = 4,
+ QMI_WLFW_CCPM_V01 = 5,
+ QMI_WLFW_QVIT_V01 = 6,
+ QMI_WLFW_CALIBRATION_V01 = 7,
+ WLFW_DRIVER_MODE_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_cal_temp_id_enum_v01 {
+ WLFW_CAL_TEMP_ID_ENUM_MIN_VAL_V01 = INT_MIN,
+ QMI_WLFW_CAL_TEMP_IDX_0_V01 = 0,
+ QMI_WLFW_CAL_TEMP_IDX_1_V01 = 1,
+ QMI_WLFW_CAL_TEMP_IDX_2_V01 = 2,
+ QMI_WLFW_CAL_TEMP_IDX_3_V01 = 3,
+ QMI_WLFW_CAL_TEMP_IDX_4_V01 = 4,
+ WLFW_CAL_TEMP_ID_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+enum wlfw_pipedir_enum_v01 {
+ WLFW_PIPEDIR_ENUM_MIN_VAL_V01 = INT_MIN,
+ QMI_WLFW_PIPEDIR_NONE_V01 = 0,
+ QMI_WLFW_PIPEDIR_IN_V01 = 1,
+ QMI_WLFW_PIPEDIR_OUT_V01 = 2,
+ QMI_WLFW_PIPEDIR_INOUT_V01 = 3,
+ WLFW_PIPEDIR_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
+#define QMI_WLFW_CE_ATTR_FLAGS_V01 ((uint32_t)0x00)
+#define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((uint32_t)0x01)
+#define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((uint32_t)0x02)
+#define QMI_WLFW_CE_ATTR_SWIZZLE_DESCRIPTORS_V01 ((uint32_t)0x04)
+#define QMI_WLFW_CE_ATTR_DISABLE_INTR_V01 ((uint32_t)0x08)
+#define QMI_WLFW_CE_ATTR_ENABLE_POLL_V01 ((uint32_t)0x10)
+
+#define QMI_WLFW_ALREADY_REGISTERED_V01 ((uint64_t)0x01ULL)
+#define QMI_WLFW_FW_READY_V01 ((uint64_t)0x02ULL)
+#define QMI_WLFW_MSA_READY_V01 ((uint64_t)0x04ULL)
+#define QMI_WLFW_FW_MEM_READY_V01 ((uint64_t)0x08ULL)
+
+#define QMI_WLFW_FW_REJUVENATE_V01 ((uint64_t)0x01ULL)
+
+struct wlfw_ce_tgt_pipe_cfg_s_v01 {
+ u32 pipe_num;
+ enum wlfw_pipedir_enum_v01 pipe_dir;
+ u32 nentries;
+ u32 nbytes_max;
+ u32 flags;
+};
+
+struct wlfw_ce_svc_pipe_cfg_s_v01 {
+ u32 service_id;
+ enum wlfw_pipedir_enum_v01 pipe_dir;
+ u32 pipe_num;
+};
+
+struct wlfw_shadow_reg_cfg_s_v01 {
+ u16 id;
+ u16 offset;
+};
+
+struct wlfw_shadow_reg_v2_cfg_s_v01 {
+ u32 addr;
+};
+
+struct wlfw_memory_region_info_s_v01 {
+ u64 region_addr;
+ u32 size;
+ u8 secure_flag;
+};
+
+struct wlfw_rf_chip_info_s_v01 {
+ u32 chip_id;
+ u32 chip_family;
+};
+
+struct wlfw_rf_board_info_s_v01 {
+ u32 board_id;
+};
+
+struct wlfw_soc_info_s_v01 {
+ u32 soc_id;
+};
+
+struct wlfw_fw_version_info_s_v01 {
+ u32 fw_version;
+ char fw_build_timestamp[QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1];
+};
+
+struct wlfw_ind_register_req_msg_v01 {
+ u8 fw_ready_enable_valid;
+ u8 fw_ready_enable;
+ u8 initiate_cal_download_enable_valid;
+ u8 initiate_cal_download_enable;
+ u8 initiate_cal_update_enable_valid;
+ u8 initiate_cal_update_enable;
+ u8 msa_ready_enable_valid;
+ u8 msa_ready_enable;
+ u8 pin_connect_result_enable_valid;
+ u8 pin_connect_result_enable;
+ u8 client_id_valid;
+ u32 client_id;
+ u8 request_mem_enable_valid;
+ u8 request_mem_enable;
+ u8 fw_mem_ready_enable_valid;
+ u8 fw_mem_ready_enable;
+ u8 cold_boot_cal_done_enable_valid;
+ u8 cold_boot_cal_done_enable;
+ u8 rejuvenate_enable_valid;
+ u32 rejuvenate_enable;
+};
+
+#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 46
+extern struct elem_info wlfw_ind_register_req_msg_v01_ei[];
+
+struct wlfw_ind_register_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 fw_status_valid;
+ u64 fw_status;
+};
+
+#define WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN 18
+extern struct elem_info wlfw_ind_register_resp_msg_v01_ei[];
+
+struct wlfw_fw_ready_ind_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_FW_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_fw_ready_ind_msg_v01_ei[];
+
+struct wlfw_msa_ready_ind_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_msa_ready_ind_msg_v01_ei[];
+
+struct wlfw_pin_connect_result_ind_msg_v01 {
+ u8 pwr_pin_result_valid;
+ u32 pwr_pin_result;
+ u8 phy_io_pin_result_valid;
+ u32 phy_io_pin_result;
+ u8 rf_pin_result_valid;
+ u32 rf_pin_result;
+};
+
+#define WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN 21
+extern struct elem_info wlfw_pin_connect_result_ind_msg_v01_ei[];
+
+struct wlfw_wlan_mode_req_msg_v01 {
+ enum wlfw_driver_mode_enum_v01 mode;
+ u8 hw_debug_valid;
+ u8 hw_debug;
+};
+
+#define WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct elem_info wlfw_wlan_mode_req_msg_v01_ei[];
+
+struct wlfw_wlan_mode_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_wlan_mode_resp_msg_v01_ei[];
+
+struct wlfw_wlan_cfg_req_msg_v01 {
+ u8 host_version_valid;
+ char host_version[QMI_WLFW_MAX_STR_LEN_V01 + 1];
+ u8 tgt_cfg_valid;
+ u32 tgt_cfg_len;
+ struct wlfw_ce_tgt_pipe_cfg_s_v01 tgt_cfg[QMI_WLFW_MAX_NUM_CE_V01];
+ u8 svc_cfg_valid;
+ u32 svc_cfg_len;
+ struct wlfw_ce_svc_pipe_cfg_s_v01 svc_cfg[QMI_WLFW_MAX_NUM_SVC_V01];
+ u8 shadow_reg_valid;
+ u32 shadow_reg_len;
+ struct wlfw_shadow_reg_cfg_s_v01
+ shadow_reg[QMI_WLFW_MAX_NUM_SHADOW_REG_V01];
+ u8 shadow_reg_v2_valid;
+ u32 shadow_reg_v2_len;
+ struct wlfw_shadow_reg_v2_cfg_s_v01
+ shadow_reg_v2[QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01];
+};
+
+#define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 803
+extern struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[];
+
+struct wlfw_wlan_cfg_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_wlan_cfg_resp_msg_v01_ei[];
+
+struct wlfw_cap_req_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_cap_req_msg_v01_ei[];
+
+struct wlfw_cap_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 chip_info_valid;
+ struct wlfw_rf_chip_info_s_v01 chip_info;
+ u8 board_info_valid;
+ struct wlfw_rf_board_info_s_v01 board_info;
+ u8 soc_info_valid;
+ struct wlfw_soc_info_s_v01 soc_info;
+ u8 fw_version_info_valid;
+ struct wlfw_fw_version_info_s_v01 fw_version_info;
+ u8 fw_build_id_valid;
+ char fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1];
+};
+
+#define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 203
+extern struct elem_info wlfw_cap_resp_msg_v01_ei[];
+
+struct wlfw_bdf_download_req_msg_v01 {
+ u8 valid;
+ u8 file_id_valid;
+ enum wlfw_cal_temp_id_enum_v01 file_id;
+ u8 total_size_valid;
+ u32 total_size;
+ u8 seg_id_valid;
+ u32 seg_id;
+ u8 data_valid;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+ u8 end_valid;
+ u8 end;
+};
+
+#define WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6178
+extern struct elem_info wlfw_bdf_download_req_msg_v01_ei[];
+
+struct wlfw_bdf_download_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_bdf_download_resp_msg_v01_ei[];
+
+struct wlfw_cal_report_req_msg_v01 {
+ u32 meta_data_len;
+ enum wlfw_cal_temp_id_enum_v01 meta_data[QMI_WLFW_MAX_NUM_CAL_V01];
+};
+
+#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 24
+extern struct elem_info wlfw_cal_report_req_msg_v01_ei[];
+
+struct wlfw_cal_report_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_CAL_REPORT_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_cal_report_resp_msg_v01_ei[];
+
+struct wlfw_initiate_cal_download_ind_msg_v01 {
+ enum wlfw_cal_temp_id_enum_v01 cal_id;
+};
+
+#define WLFW_INITIATE_CAL_DOWNLOAD_IND_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[];
+
+struct wlfw_cal_download_req_msg_v01 {
+ u8 valid;
+ u8 file_id_valid;
+ enum wlfw_cal_temp_id_enum_v01 file_id;
+ u8 total_size_valid;
+ u32 total_size;
+ u8 seg_id_valid;
+ u32 seg_id;
+ u8 data_valid;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+ u8 end_valid;
+ u8 end;
+};
+
+#define WLFW_CAL_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6178
+extern struct elem_info wlfw_cal_download_req_msg_v01_ei[];
+
+struct wlfw_cal_download_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_CAL_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_cal_download_resp_msg_v01_ei[];
+
+struct wlfw_initiate_cal_update_ind_msg_v01 {
+ enum wlfw_cal_temp_id_enum_v01 cal_id;
+ u32 total_size;
+};
+
+#define WLFW_INITIATE_CAL_UPDATE_IND_MSG_V01_MAX_MSG_LEN 14
+extern struct elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[];
+
+struct wlfw_cal_update_req_msg_v01 {
+ enum wlfw_cal_temp_id_enum_v01 cal_id;
+ u32 seg_id;
+};
+
+#define WLFW_CAL_UPDATE_REQ_MSG_V01_MAX_MSG_LEN 14
+extern struct elem_info wlfw_cal_update_req_msg_v01_ei[];
+
+struct wlfw_cal_update_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 file_id_valid;
+ enum wlfw_cal_temp_id_enum_v01 file_id;
+ u8 total_size_valid;
+ u32 total_size;
+ u8 seg_id_valid;
+ u32 seg_id;
+ u8 data_valid;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+ u8 end_valid;
+ u8 end;
+};
+
+#define WLFW_CAL_UPDATE_RESP_MSG_V01_MAX_MSG_LEN 6181
+extern struct elem_info wlfw_cal_update_resp_msg_v01_ei[];
+
+struct wlfw_msa_info_req_msg_v01 {
+ u64 msa_addr;
+ u32 size;
+};
+
+#define WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct elem_info wlfw_msa_info_req_msg_v01_ei[];
+
+struct wlfw_msa_info_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u32 mem_region_info_len;
+ struct wlfw_memory_region_info_s_v01
+ mem_region_info[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01];
+};
+
+#define WLFW_MSA_INFO_RESP_MSG_V01_MAX_MSG_LEN 37
+extern struct elem_info wlfw_msa_info_resp_msg_v01_ei[];
+
+struct wlfw_msa_ready_req_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_msa_ready_req_msg_v01_ei[];
+
+struct wlfw_msa_ready_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_MSA_READY_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_msa_ready_resp_msg_v01_ei[];
+
+struct wlfw_ini_req_msg_v01 {
+ u8 enablefwlog_valid;
+ u8 enablefwlog;
+};
+
+#define WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN 4
+extern struct elem_info wlfw_ini_req_msg_v01_ei[];
+
+struct wlfw_ini_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_ini_resp_msg_v01_ei[];
+
+struct wlfw_athdiag_read_req_msg_v01 {
+ u32 offset;
+ u32 mem_type;
+ u32 data_len;
+};
+
+#define WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN 21
+extern struct elem_info wlfw_athdiag_read_req_msg_v01_ei[];
+
+struct wlfw_athdiag_read_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 data_valid;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+};
+
+#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 6156
+extern struct elem_info wlfw_athdiag_read_resp_msg_v01_ei[];
+
+struct wlfw_athdiag_write_req_msg_v01 {
+ u32 offset;
+ u32 mem_type;
+ u32 data_len;
+ u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
+};
+
+#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 6163
+extern struct elem_info wlfw_athdiag_write_req_msg_v01_ei[];
+
+struct wlfw_athdiag_write_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_ATHDIAG_WRITE_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_athdiag_write_resp_msg_v01_ei[];
+
+struct wlfw_vbatt_req_msg_v01 {
+ u64 voltage_uv;
+};
+
+#define WLFW_VBATT_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct elem_info wlfw_vbatt_req_msg_v01_ei[];
+
+struct wlfw_vbatt_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_VBATT_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_vbatt_resp_msg_v01_ei[];
+
+struct wlfw_mac_addr_req_msg_v01 {
+ u8 mac_addr_valid;
+ u8 mac_addr[QMI_WLFW_MAC_ADDR_SIZE_V01];
+};
+
+#define WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN 9
+extern struct elem_info wlfw_mac_addr_req_msg_v01_ei[];
+
+struct wlfw_mac_addr_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_MAC_ADDR_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_mac_addr_resp_msg_v01_ei[];
+
+struct wlfw_host_cap_req_msg_v01 {
+ u8 daemon_support_valid;
+ u8 daemon_support;
+};
+
+#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 4
+extern struct elem_info wlfw_host_cap_req_msg_v01_ei[];
+
+struct wlfw_host_cap_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_HOST_CAP_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_host_cap_resp_msg_v01_ei[];
+
+struct wlfw_request_mem_ind_msg_v01 {
+ u32 size;
+};
+
+#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_request_mem_ind_msg_v01_ei[];
+
+struct wlfw_respond_mem_req_msg_v01 {
+ u64 addr;
+ u32 size;
+};
+
+#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 18
+extern struct elem_info wlfw_respond_mem_req_msg_v01_ei[];
+
+struct wlfw_respond_mem_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_RESPOND_MEM_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_respond_mem_resp_msg_v01_ei[];
+
+struct wlfw_fw_mem_ready_ind_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_FW_MEM_READY_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[];
+
+struct wlfw_cold_boot_cal_done_ind_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_COLD_BOOT_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ind_msg_v01 {
+ u8 cause_for_rejuvenation_valid;
+ u8 cause_for_rejuvenation;
+ u8 requesting_sub_system_valid;
+ u8 requesting_sub_system;
+ u8 line_number_valid;
+ u16 line_number;
+ u8 function_name_valid;
+ char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1];
+};
+
+#define WLFW_REJUVENATE_IND_MSG_V01_MAX_MSG_LEN 144
+extern struct elem_info wlfw_rejuvenate_ind_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ack_req_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_REJUVENATE_ACK_REQ_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[];
+
+struct wlfw_rejuvenate_ack_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+#define WLFW_REJUVENATE_ACK_RESP_MSG_V01_MAX_MSG_LEN 7
+extern struct elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[];
+
+struct wlfw_dynamic_feature_mask_req_msg_v01 {
+ u8 mask_valid;
+ u64 mask;
+};
+
+#define WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN 11
+extern struct elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[];
+
+struct wlfw_dynamic_feature_mask_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+ u8 prev_mask_valid;
+ u64 prev_mask;
+ u8 curr_mask_valid;
+ u64 curr_mask;
+};
+
+#define WLFW_DYNAMIC_FEATURE_MASK_RESP_MSG_V01_MAX_MSG_LEN 29
+extern struct elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[];
+
+#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index 3fef967ca1ad..75f2528b8b84 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -553,7 +553,7 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
ath10k_wmi_tlv_event_tx_pause(ar, skb);
break;
default:
- ath10k_warn(ar, "Unknown eventid: %d\n", id);
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "Unknown eventid: %d\n", id);
break;
}
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 4dd60b74853d..cbbba8d79e6b 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1799,6 +1799,9 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
{
int ret = -EOPNOTSUPP;
+ if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))
+ return -ESHUTDOWN;
+
might_sleep();
if (cmd_id == WMI_CMD_UNSUPPORTED) {
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index dc44cfef7517..16e052d02c94 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -502,8 +502,7 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
break;
return -EOPNOTSUPP;
default:
- WARN_ON(1);
- return -EINVAL;
+ return -EOPNOTSUPP;
}
mutex_lock(&ah->lock);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
index 694ca2e680e5..74670e08e6da 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
@@ -73,13 +73,13 @@
#define AR9300_OTP_BASE \
((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30000 : 0x14000)
#define AR9300_OTP_STATUS \
- ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x30018 : 0x15f18)
+ ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x31018 : 0x15f18)
#define AR9300_OTP_STATUS_TYPE 0x7
#define AR9300_OTP_STATUS_VALID 0x4
#define AR9300_OTP_STATUS_ACCESS_BUSY 0x2
#define AR9300_OTP_STATUS_SM_BUSY 0x1
#define AR9300_OTP_READ_DATA \
- ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3001c : 0x15f1c)
+ ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) ? 0x3101c : 0x15f1c)
enum targetPowerHTRates {
HT_TARGET_RATE_0_8_16,
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index b42f4a963ef4..a660e40f2df1 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -959,6 +959,7 @@ struct ath_softc {
struct survey_info *cur_survey;
struct survey_info survey[ATH9K_NUM_CHANNELS];
+ spinlock_t intr_lock;
struct tasklet_struct intr_tq;
struct tasklet_struct bcon_tasklet;
struct ath_hw *sc_ah;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index bc70ce62bc03..0f5672f5c9ba 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -619,6 +619,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
common->bt_ant_diversity = 1;
spin_lock_init(&common->cc_lock);
+ spin_lock_init(&sc->intr_lock);
spin_lock_init(&sc->sc_serial_rw);
spin_lock_init(&sc->sc_pm_lock);
spin_lock_init(&sc->chan_lock);
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index bba85d1a6cd1..d937c39b3a0b 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -805,21 +805,12 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah)
}
EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
-void ath9k_hw_enable_interrupts(struct ath_hw *ah)
+static void __ath9k_hw_enable_interrupts(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
u32 sync_default = AR_INTR_SYNC_DEFAULT;
u32 async_mask;
- if (!(ah->imask & ATH9K_INT_GLOBAL))
- return;
-
- if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
- ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
- atomic_read(&ah->intr_ref_cnt));
- return;
- }
-
if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
AR_SREV_9561(ah))
sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
@@ -841,6 +832,39 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
ath_dbg(common, INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
}
+
+void ath9k_hw_resume_interrupts(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (!(ah->imask & ATH9K_INT_GLOBAL))
+ return;
+
+ if (atomic_read(&ah->intr_ref_cnt) != 0) {
+ ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
+ atomic_read(&ah->intr_ref_cnt));
+ return;
+ }
+
+ __ath9k_hw_enable_interrupts(ah);
+}
+EXPORT_SYMBOL(ath9k_hw_resume_interrupts);
+
+void ath9k_hw_enable_interrupts(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+
+ if (!(ah->imask & ATH9K_INT_GLOBAL))
+ return;
+
+ if (!atomic_inc_and_test(&ah->intr_ref_cnt)) {
+ ath_dbg(common, INTERRUPT, "Do not enable IER ref count %d\n",
+ atomic_read(&ah->intr_ref_cnt));
+ return;
+ }
+
+ __ath9k_hw_enable_interrupts(ah);
+}
EXPORT_SYMBOL(ath9k_hw_enable_interrupts);
void ath9k_hw_set_interrupts(struct ath_hw *ah)
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index 7fbf7f965f61..1b63d26f30ce 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -748,6 +748,7 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah);
void ath9k_hw_enable_interrupts(struct ath_hw *ah);
void ath9k_hw_disable_interrupts(struct ath_hw *ah);
void ath9k_hw_kill_interrupts(struct ath_hw *ah);
+void ath9k_hw_resume_interrupts(struct ath_hw *ah);
void ar9002_hw_attach_mac_ops(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 7be31f27266c..3abc64574116 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -373,21 +373,20 @@ void ath9k_tasklet(unsigned long data)
struct ath_common *common = ath9k_hw_common(ah);
enum ath_reset_type type;
unsigned long flags;
- u32 status = sc->intrstatus;
+ u32 status;
u32 rxmask;
+ spin_lock_irqsave(&sc->intr_lock, flags);
+ status = sc->intrstatus;
+ sc->intrstatus = 0;
+ spin_unlock_irqrestore(&sc->intr_lock, flags);
+
ath9k_ps_wakeup(sc);
spin_lock(&sc->sc_pcu_lock);
if (status & ATH9K_INT_FATAL) {
type = RESET_TYPE_FATAL_INT;
ath9k_queue_reset(sc, type);
-
- /*
- * Increment the ref. counter here so that
- * interrupts are enabled in the reset routine.
- */
- atomic_inc(&ah->intr_ref_cnt);
ath_dbg(common, RESET, "FATAL: Skipping interrupts\n");
goto out;
}
@@ -403,11 +402,6 @@ void ath9k_tasklet(unsigned long data)
type = RESET_TYPE_BB_WATCHDOG;
ath9k_queue_reset(sc, type);
- /*
- * Increment the ref. counter here so that
- * interrupts are enabled in the reset routine.
- */
- atomic_inc(&ah->intr_ref_cnt);
ath_dbg(common, RESET,
"BB_WATCHDOG: Skipping interrupts\n");
goto out;
@@ -420,7 +414,6 @@ void ath9k_tasklet(unsigned long data)
if ((sc->gtt_cnt >= MAX_GTT_CNT) && !ath9k_hw_check_alive(ah)) {
type = RESET_TYPE_TX_GTT;
ath9k_queue_reset(sc, type);
- atomic_inc(&ah->intr_ref_cnt);
ath_dbg(common, RESET,
"GTT: Skipping interrupts\n");
goto out;
@@ -477,7 +470,7 @@ void ath9k_tasklet(unsigned long data)
ath9k_btcoex_handle_interrupt(sc, status);
/* re-enable hardware interrupt */
- ath9k_hw_enable_interrupts(ah);
+ ath9k_hw_resume_interrupts(ah);
out:
spin_unlock(&sc->sc_pcu_lock);
ath9k_ps_restore(sc);
@@ -541,7 +534,9 @@ irqreturn_t ath_isr(int irq, void *dev)
return IRQ_NONE;
/* Cache the status */
- sc->intrstatus = status;
+ spin_lock(&sc->intr_lock);
+ sc->intrstatus |= status;
+ spin_unlock(&sc->intr_lock);
if (status & SCHED_INTR)
sched = true;
@@ -587,7 +582,7 @@ chip_reset:
if (sched) {
/* turn off every interrupt */
- ath9k_hw_disable_interrupts(ah);
+ ath9k_hw_kill_interrupts(ah);
tasklet_schedule(&sc->intr_tq);
}
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index acd5347f2cae..923fe470360c 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -475,22 +475,23 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
}
mutex_unlock(&wil->p2p_wdev_mutex);
- /* social scan on P2P_DEVICE is handled as p2p search */
- if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
- wil_p2p_is_social_scan(request)) {
+ if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) {
if (!wil->p2p.p2p_dev_started) {
wil_err(wil, "P2P search requested on stopped P2P device\n");
rc = -EIO;
goto out;
}
- wil->scan_request = request;
- wil->radio_wdev = wdev;
- rc = wil_p2p_search(wil, request);
- if (rc) {
- wil->radio_wdev = wil_to_wdev(wil);
- wil->scan_request = NULL;
+ /* social scan on P2P_DEVICE is handled as p2p search */
+ if (wil_p2p_is_social_scan(request)) {
+ wil->scan_request = request;
+ wil->radio_wdev = wdev;
+ rc = wil_p2p_search(wil, request);
+ if (rc) {
+ wil->radio_wdev = wil_to_wdev(wil);
+ wil->scan_request = NULL;
+ }
+ goto out;
}
- goto out;
}
(void)wil_p2p_stop_discovery(wil);
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 958c96b75fbb..01a27335ec34 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -130,9 +130,15 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
u32 *d = dst;
const volatile u32 __iomem *s = src;
- /* size_t is unsigned, if (count%4 != 0) it will wrap */
- for (count += 4; count > 4; count -= 4)
+ for (; count >= 4; count -= 4)
*d++ = __raw_readl(s++);
+
+ if (unlikely(count)) {
+ /* count can be 1..3 */
+ u32 tmp = __raw_readl(s);
+
+ memcpy(d, &tmp, count);
+ }
}
void wil_memcpy_fromio_halp_vote(struct wil6210_priv *wil, void *dst,
@@ -149,8 +155,16 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
volatile u32 __iomem *d = dst;
const u32 *s = src;
- for (count += 4; count > 4; count -= 4)
+ for (; count >= 4; count -= 4)
__raw_writel(*s++, d++);
+
+ if (unlikely(count)) {
+ /* count can be 1..3 */
+ u32 tmp = 0;
+
+ memcpy(&tmp, s, count);
+ __raw_writel(tmp, d);
+ }
}
void wil_memcpy_toio_halp_vote(struct wil6210_priv *wil,
diff --git a/drivers/net/wireless/cnss_genl/Kconfig b/drivers/net/wireless/cnss_genl/Kconfig
new file mode 100644
index 000000000000..f1b8a586ec90
--- /dev/null
+++ b/drivers/net/wireless/cnss_genl/Kconfig
@@ -0,0 +1,7 @@
+config CNSS_GENL
+ tristate "CNSS Generic Netlink Socket Driver"
+ ---help---
+ This module creates generic netlink family "CLD80211". This can be
+ used by cld driver and userspace utilities to communicate over
+ netlink sockets. This module creates different multicast groups to
+ facilitate the same.
diff --git a/drivers/net/wireless/cnss_genl/Makefile b/drivers/net/wireless/cnss_genl/Makefile
new file mode 100644
index 000000000000..9431c9e596bb
--- /dev/null
+++ b/drivers/net/wireless/cnss_genl/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_CNSS_GENL) := cnss_nl.o
diff --git a/drivers/net/wireless/cnss_genl/cnss_nl.c b/drivers/net/wireless/cnss_genl/cnss_nl.c
new file mode 100644
index 000000000000..fafd9ce4b4c4
--- /dev/null
+++ b/drivers/net/wireless/cnss_genl/cnss_nl.c
@@ -0,0 +1,204 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <net/genetlink.h>
+#include <net/cnss_nl.h>
+#include <linux/module.h>
+
+#define CLD80211_GENL_NAME "cld80211"
+
+#define CLD80211_MULTICAST_GROUP_SVC_MSGS "svc_msgs"
+#define CLD80211_MULTICAST_GROUP_HOST_LOGS "host_logs"
+#define CLD80211_MULTICAST_GROUP_FW_LOGS "fw_logs"
+#define CLD80211_MULTICAST_GROUP_PER_PKT_STATS "per_pkt_stats"
+#define CLD80211_MULTICAST_GROUP_DIAG_EVENTS "diag_events"
+#define CLD80211_MULTICAST_GROUP_FATAL_EVENTS "fatal_events"
+#define CLD80211_MULTICAST_GROUP_OEM_MSGS "oem_msgs"
+
+static const struct genl_multicast_group nl_mcgrps[] = {
+ [CLD80211_MCGRP_SVC_MSGS] = { .name =
+ CLD80211_MULTICAST_GROUP_SVC_MSGS},
+ [CLD80211_MCGRP_HOST_LOGS] = { .name =
+ CLD80211_MULTICAST_GROUP_HOST_LOGS},
+ [CLD80211_MCGRP_FW_LOGS] = { .name =
+ CLD80211_MULTICAST_GROUP_FW_LOGS},
+ [CLD80211_MCGRP_PER_PKT_STATS] = { .name =
+ CLD80211_MULTICAST_GROUP_PER_PKT_STATS},
+ [CLD80211_MCGRP_DIAG_EVENTS] = { .name =
+ CLD80211_MULTICAST_GROUP_DIAG_EVENTS},
+ [CLD80211_MCGRP_FATAL_EVENTS] = { .name =
+ CLD80211_MULTICAST_GROUP_FATAL_EVENTS},
+ [CLD80211_MCGRP_OEM_MSGS] = { .name =
+ CLD80211_MULTICAST_GROUP_OEM_MSGS},
+};
+
+struct cld_ops {
+ cld80211_cb cb;
+ void *cb_ctx;
+};
+
+struct cld80211_nl_data {
+ struct cld_ops cld_ops[CLD80211_MAX_COMMANDS];
+};
+
+static struct cld80211_nl_data nl_data;
+
+static inline struct cld80211_nl_data *get_local_ctx(void)
+{
+ return &nl_data;
+}
+
+static struct genl_ops nl_ops[CLD80211_MAX_COMMANDS];
+
+/* policy for the attributes */
+static const struct nla_policy cld80211_policy[CLD80211_ATTR_MAX + 1] = {
+ [CLD80211_ATTR_VENDOR_DATA] = { .type = NLA_NESTED },
+ [CLD80211_ATTR_DATA] = { .type = NLA_BINARY,
+ .len = CLD80211_MAX_NL_DATA },
+};
+
+static int cld80211_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
+ struct genl_info *info)
+{
+ u8 cmd_id = ops->cmd;
+ struct cld80211_nl_data *nl = get_local_ctx();
+
+ if (cmd_id < 1 || cmd_id > CLD80211_MAX_COMMANDS) {
+ pr_err("CLD80211: Command Not supported: %u\n", cmd_id);
+ return -EOPNOTSUPP;
+ }
+ info->user_ptr[0] = nl->cld_ops[cmd_id - 1].cb;
+ info->user_ptr[1] = nl->cld_ops[cmd_id - 1].cb_ctx;
+
+ return 0;
+}
+
+/* The netlink family */
+static struct genl_family cld80211_fam = {
+ .id = GENL_ID_GENERATE,
+ .name = CLD80211_GENL_NAME,
+ .hdrsize = 0, /* no private header */
+ .version = 1, /* no particular meaning now */
+ .maxattr = CLD80211_ATTR_MAX,
+ .netnsok = true,
+ .pre_doit = cld80211_pre_doit,
+ .post_doit = NULL,
+};
+
+int register_cld_cmd_cb(u8 cmd_id, cld80211_cb func, void *cb_ctx)
+{
+ struct cld80211_nl_data *nl = get_local_ctx();
+
+ pr_debug("CLD80211: Registering command: %d\n", cmd_id);
+ if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) {
+ pr_debug("CLD80211: invalid command: %d\n", cmd_id);
+ return -EINVAL;
+ }
+
+ nl->cld_ops[cmd_id - 1].cb = func;
+ nl->cld_ops[cmd_id - 1].cb_ctx = cb_ctx;
+
+ return 0;
+}
+EXPORT_SYMBOL(register_cld_cmd_cb);
+
+int deregister_cld_cmd_cb(u8 cmd_id)
+{
+ struct cld80211_nl_data *nl = get_local_ctx();
+
+ pr_debug("CLD80211: De-registering command: %d\n", cmd_id);
+ if (!cmd_id || cmd_id > CLD80211_MAX_COMMANDS) {
+ pr_debug("CLD80211: invalid command: %d\n", cmd_id);
+ return -EINVAL;
+ }
+
+ nl->cld_ops[cmd_id - 1].cb = NULL;
+ nl->cld_ops[cmd_id - 1].cb_ctx = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(deregister_cld_cmd_cb);
+
+struct genl_family *cld80211_get_genl_family(void)
+{
+ return &cld80211_fam;
+}
+EXPORT_SYMBOL(cld80211_get_genl_family);
+
+static int cld80211_doit(struct sk_buff *skb, struct genl_info *info)
+{
+ cld80211_cb cld_cb;
+ void *cld_ctx;
+
+ cld_cb = info->user_ptr[0];
+
+ if (!cld_cb) {
+ pr_err("CLD80211: Not supported\n");
+ return -EOPNOTSUPP;
+ }
+ cld_ctx = info->user_ptr[1];
+
+ if (info->attrs[CLD80211_ATTR_VENDOR_DATA]) {
+ cld_cb(nla_data(info->attrs[CLD80211_ATTR_VENDOR_DATA]),
+ nla_len(info->attrs[CLD80211_ATTR_VENDOR_DATA]),
+ cld_ctx, info->snd_portid);
+ } else {
+ pr_err("CLD80211: No CLD80211_ATTR_VENDOR_DATA\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __cld80211_init(void)
+{
+ int err, i;
+
+ memset(&nl_ops[0], 0, sizeof(nl_ops));
+
+ pr_info("CLD80211: Initializing\n");
+ for (i = 0; i < CLD80211_MAX_COMMANDS; i++) {
+ nl_ops[i].cmd = i + 1;
+ nl_ops[i].doit = cld80211_doit;
+ nl_ops[i].flags = GENL_ADMIN_PERM;
+ nl_ops[i].policy = cld80211_policy;
+ }
+
+ err = genl_register_family_with_ops_groups(&cld80211_fam, nl_ops,
+ nl_mcgrps);
+ if (err) {
+ pr_err("CLD80211: Failed to register cld80211 family: %d\n",
+ err);
+ }
+
+ return err;
+}
+
+static void __cld80211_exit(void)
+{
+ genl_unregister_family(&cld80211_fam);
+}
+
+static int __init cld80211_init(void)
+{
+ return __cld80211_init();
+}
+
+static void __exit cld80211_exit(void)
+{
+ __cld80211_exit();
+}
+
+module_init(cld80211_init);
+module_exit(cld80211_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CNSS generic netlink module");
diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
index 913f756f9520..e93416ebd343 100644
--- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
+++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
@@ -11,10 +11,15 @@
*/
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/seq_file.h>
#include <linux/err.h>
#include <linux/stacktrace.h>
#include <linux/wcnss_wlan.h>
#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#ifdef CONFIG_WCNSS_SKB_PRE_ALLOC
+#include <linux/skbuff.h>
+#endif
static DEFINE_SPINLOCK(alloc_lock);
@@ -22,6 +27,11 @@ static DEFINE_SPINLOCK(alloc_lock);
#define WCNSS_MAX_STACK_TRACE 64
#endif
+#define PRE_ALLOC_DEBUGFS_DIR "cnss-prealloc"
+#define PRE_ALLOC_DEBUGFS_FILE_OBJ "status"
+
+static struct dentry *debug_base;
+
struct wcnss_prealloc {
int occupied;
unsigned int size;
@@ -216,6 +226,8 @@ void wcnss_prealloc_check_memory_leak(void)
}
}
+#else
+void wcnss_prealloc_check_memory_leak(void) {}
#endif
int wcnss_pre_alloc_reset(void)
@@ -233,14 +245,89 @@ int wcnss_pre_alloc_reset(void)
return n;
}
+int prealloc_memory_stats_show(struct seq_file *fp, void *data)
+{
+ int i = 0;
+ int used_slots = 0, free_slots = 0;
+ unsigned int tsize = 0, tused = 0, size = 0;
+
+ seq_puts(fp, "\nSlot_Size(Kb)\t\t[Used : Free]\n");
+ for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
+ tsize += wcnss_allocs[i].size;
+ if (size != wcnss_allocs[i].size) {
+ if (size) {
+ seq_printf(
+ fp, "[%d : %d]\n",
+ used_slots, free_slots);
+ }
+
+ size = wcnss_allocs[i].size;
+ used_slots = 0;
+ free_slots = 0;
+ seq_printf(fp, "%d Kb\t\t\t", size / 1024);
+ }
+
+ if (wcnss_allocs[i].occupied) {
+ tused += wcnss_allocs[i].size;
+ ++used_slots;
+ } else {
+ ++free_slots;
+ }
+ }
+ seq_printf(fp, "[%d : %d]\n", used_slots, free_slots);
+
+ /* Convert byte to Kb */
+ if (tsize)
+ tsize = tsize / 1024;
+ if (tused)
+ tused = tused / 1024;
+ seq_printf(fp, "\nMemory Status:\nTotal Memory: %dKb\n", tsize);
+ seq_printf(fp, "Used: %dKb\nFree: %dKb\n", tused, tsize - tused);
+
+ return 0;
+}
+
+int prealloc_memory_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, prealloc_memory_stats_show, NULL);
+}
+
+static const struct file_operations prealloc_memory_stats_fops = {
+ .owner = THIS_MODULE,
+ .open = prealloc_memory_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static int __init wcnss_pre_alloc_init(void)
{
- return wcnss_prealloc_init();
+ int ret;
+
+ ret = wcnss_prealloc_init();
+ if (ret) {
+ pr_err("%s: Failed to init the prealloc pool\n", __func__);
+ return ret;
+ }
+
+ debug_base = debugfs_create_dir(PRE_ALLOC_DEBUGFS_DIR, NULL);
+ if (IS_ERR_OR_NULL(debug_base)) {
+ pr_err("%s: Failed to create debugfs dir\n", __func__);
+ } else if (IS_ERR_OR_NULL(debugfs_create_file(
+ PRE_ALLOC_DEBUGFS_FILE_OBJ,
+ 0644, debug_base, NULL,
+ &prealloc_memory_stats_fops))) {
+ pr_err("%s: Failed to create debugfs file\n", __func__);
+ debugfs_remove_recursive(debug_base);
+ }
+
+ return ret;
}
static void __exit wcnss_pre_alloc_exit(void)
{
wcnss_prealloc_deinit();
+ debugfs_remove_recursive(debug_base);
}
module_init(wcnss_pre_alloc_init);
diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.h b/drivers/net/wireless/realtek/rtlwifi/pci.h
index 5da6703942d9..672f81ea02d0 100644
--- a/drivers/net/wireless/realtek/rtlwifi/pci.h
+++ b/drivers/net/wireless/realtek/rtlwifi/pci.h
@@ -275,10 +275,10 @@ struct mp_adapter {
};
struct rtl_pci_priv {
+ struct bt_coexist_info bt_coexist;
+ struct rtl_led_ctl ledctl;
struct rtl_pci dev;
struct mp_adapter ndis_adapter;
- struct rtl_led_ctl ledctl;
- struct bt_coexist_info bt_coexist;
};
#define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv))
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
index 5f14308e8eb3..b1601441991d 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
@@ -1003,7 +1003,7 @@ static void _rtl92ee_hw_configure(struct ieee80211_hw *hw)
rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x100a);
/* Note Data sheet don't define */
- rtl_write_word(rtlpriv, 0x4C7, 0x80);
+ rtl_write_byte(rtlpriv, 0x4C7, 0x80);
rtl_write_byte(rtlpriv, REG_RX_PKT_LIMIT, 0x20);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
index bbb789f8990b..c2103e7a8132 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
@@ -1127,7 +1127,7 @@ static u8 _rtl8821ae_dbi_read(struct rtl_priv *rtlpriv, u16 addr)
}
if (0 == tmp) {
read_addr = REG_DBI_RDATA + addr % 4;
- ret = rtl_read_word(rtlpriv, read_addr);
+ ret = rtl_read_byte(rtlpriv, read_addr);
}
return ret;
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c
index aac1ed3f7bb4..ad8390d2997b 100644
--- a/drivers/net/wireless/realtek/rtlwifi/usb.c
+++ b/drivers/net/wireless/realtek/rtlwifi/usb.c
@@ -834,12 +834,30 @@ static void rtl_usb_stop(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
+ struct urb *urb;
/* should after adapter start and interrupt enable. */
set_hal_stop(rtlhal);
cancel_work_sync(&rtlpriv->works.fill_h2c_cmd);
/* Enable software */
SET_USB_STOP(rtlusb);
+
+ /* free pre-allocated URBs from rtl_usb_start() */
+ usb_kill_anchored_urbs(&rtlusb->rx_submitted);
+
+ tasklet_kill(&rtlusb->rx_work_tasklet);
+ cancel_work_sync(&rtlpriv->works.lps_change_work);
+
+ flush_workqueue(rtlpriv->works.rtl_wq);
+
+ skb_queue_purge(&rtlusb->rx_queue);
+
+ while ((urb = usb_get_from_anchor(&rtlusb->rx_cleanup_urbs))) {
+ usb_free_coherent(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+ }
+
rtlpriv->cfg->ops->hw_disable(hw);
}
@@ -1073,6 +1091,7 @@ int rtl_usb_probe(struct usb_interface *intf,
return -ENOMEM;
}
rtlpriv = hw->priv;
+ rtlpriv->hw = hw;
rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32),
GFP_KERNEL);
if (!rtlpriv->usb_data)
diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.h b/drivers/net/wireless/realtek/rtlwifi/usb.h
index 685273ca9561..441c4412130c 100644
--- a/drivers/net/wireless/realtek/rtlwifi/usb.h
+++ b/drivers/net/wireless/realtek/rtlwifi/usb.h
@@ -150,8 +150,9 @@ struct rtl_usb {
};
struct rtl_usb_priv {
- struct rtl_usb dev;
+ struct bt_coexist_info bt_coexist;
struct rtl_led_ctl ledctl;
+ struct rtl_usb dev;
};
#define rtl_usbpriv(hw) (((struct rtl_usb_priv *)(rtl_priv(hw))->priv))
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index 60654d524858..ecc6fb9ca92f 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -1623,7 +1623,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev,
node = dev_to_node(&ndev->dev);
- free_queue = ffs(nt->qp_bitmap);
+ free_queue = ffs(nt->qp_bitmap_free);
if (!free_queue)
goto err;
@@ -2082,9 +2082,8 @@ module_init(ntb_transport_init);
static void __exit ntb_transport_exit(void)
{
- debugfs_remove_recursive(nt_debugfs_dir);
-
ntb_unregister_client(&ntb_transport_client);
bus_unregister(&ntb_transport_bus);
+ debugfs_remove_recursive(nt_debugfs_dir);
}
module_exit(ntb_transport_exit);
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index 62120c38d56b..aae7379af4e4 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1534,6 +1534,7 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id)
static int find_pmem_label_set(struct nd_region *nd_region,
struct nd_namespace_pmem *nspm)
{
+ u64 altcookie = nd_region_interleave_set_altcookie(nd_region);
u64 cookie = nd_region_interleave_set_cookie(nd_region);
struct nd_namespace_label *nd_label;
u8 select_id[NSLABEL_UUID_LEN];
@@ -1542,8 +1543,10 @@ static int find_pmem_label_set(struct nd_region *nd_region,
int rc = -ENODEV, l;
u16 i;
- if (cookie == 0)
+ if (cookie == 0) {
+ dev_dbg(&nd_region->dev, "invalid interleave-set-cookie\n");
return -ENXIO;
+ }
/*
* Find a complete set of labels by uuid. By definition we can start
@@ -1552,13 +1555,24 @@ static int find_pmem_label_set(struct nd_region *nd_region,
for_each_label(l, nd_label, nd_region->mapping[0].labels) {
u64 isetcookie = __le64_to_cpu(nd_label->isetcookie);
- if (isetcookie != cookie)
- continue;
+ if (isetcookie != cookie) {
+ dev_dbg(&nd_region->dev, "invalid cookie in label: %pUb\n",
+ nd_label->uuid);
+ if (isetcookie != altcookie)
+ continue;
+
+ dev_dbg(&nd_region->dev, "valid altcookie in label: %pUb\n",
+ nd_label->uuid);
+ }
+
+ for (i = 0; nd_region->ndr_mappings; i++) {
+ if (has_uuid_at_pos(nd_region, nd_label->uuid, cookie, i))
+ continue;
+ if (has_uuid_at_pos(nd_region, nd_label->uuid, altcookie, i))
+ continue;
+ break;
+ }
- for (i = 0; nd_region->ndr_mappings; i++)
- if (!has_uuid_at_pos(nd_region, nd_label->uuid,
- cookie, i))
- break;
if (i < nd_region->ndr_mappings) {
/*
* Give up if we don't find an instance of a
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 417e521d299c..fc870e55bb66 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -245,6 +245,7 @@ struct nd_region *to_nd_region(struct device *dev);
int nd_region_to_nstype(struct nd_region *nd_region);
int nd_region_register_namespaces(struct nd_region *nd_region, int *err);
u64 nd_region_interleave_set_cookie(struct nd_region *nd_region);
+u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region);
void nvdimm_bus_lock(struct device *dev);
void nvdimm_bus_unlock(struct device *dev);
bool is_nvdimm_bus_locked(struct device *dev);
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index 9521696c9385..dc2e919daa39 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -379,6 +379,15 @@ u64 nd_region_interleave_set_cookie(struct nd_region *nd_region)
return 0;
}
+u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region)
+{
+ struct nd_interleave_set *nd_set = nd_region->nd_set;
+
+ if (nd_set)
+ return nd_set->altcookie;
+ return 0;
+}
+
/*
* Upon successful probe/remove, take/release a reference on the
* associated interleave set (if present), and plant new btt + namespace
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index 584ad96c703f..eade4f85632a 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -2511,6 +2511,48 @@ int msm_pcie_debug_info(struct pci_dev *dev, u32 option, u32 base,
}
EXPORT_SYMBOL(msm_pcie_debug_info);
+#ifdef CONFIG_SYSFS
+static ssize_t msm_pcie_enumerate_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct msm_pcie_dev_t *pcie_dev = (struct msm_pcie_dev_t *)
+ dev_get_drvdata(dev);
+
+ if (pcie_dev)
+ msm_pcie_enumerate(pcie_dev->rc_idx);
+
+ return count;
+}
+
+static DEVICE_ATTR(enumerate, S_IWUSR, NULL, msm_pcie_enumerate_store);
+
+static void msm_pcie_sysfs_init(struct msm_pcie_dev_t *dev)
+{
+ int ret;
+
+ ret = device_create_file(&dev->pdev->dev, &dev_attr_enumerate);
+ if (ret)
+ PCIE_DBG_FS(dev,
+ "RC%d: failed to create sysfs enumerate node\n",
+ dev->rc_idx);
+}
+
+static void msm_pcie_sysfs_exit(struct msm_pcie_dev_t *dev)
+{
+ if (dev->pdev)
+ device_remove_file(&dev->pdev->dev, &dev_attr_enumerate);
+}
+#else
+static void msm_pcie_sysfs_init(struct msm_pcie_dev_t *dev)
+{
+}
+
+static void msm_pcie_sysfs_exit(struct msm_pcie_dev_t *dev)
+{
+}
+#endif
+
#ifdef CONFIG_DEBUG_FS
static struct dentry *dent_msm_pcie;
static struct dentry *dfile_rc_sel;
@@ -4600,6 +4642,8 @@ int msm_pcie_enable(struct msm_pcie_dev_t *dev, u32 options)
do {
usleep_range(LINK_UP_TIMEOUT_US_MIN, LINK_UP_TIMEOUT_US_MAX);
val = readl_relaxed(dev->elbi + PCIE20_ELBI_SYS_STTS);
+ PCIE_DBG(dev, "PCIe RC%d: LTSSM_STATE:0x%x\n",
+ dev->rc_idx, (val >> 12) & 0x3f);
} while ((!(val & XMLH_LINK_UP) ||
!msm_pcie_confirm_linkup(dev, false, false, NULL))
&& (link_check_count++ < LINK_UP_CHECK_MAX_COUNT));
@@ -6277,6 +6321,9 @@ static int msm_pcie_probe(struct platform_device *pdev)
msm_pcie_dev[rc_idx].pcidev_table[i].registered = true;
}
+ dev_set_drvdata(&msm_pcie_dev[rc_idx].pdev->dev, &msm_pcie_dev[rc_idx]);
+ msm_pcie_sysfs_init(&msm_pcie_dev[rc_idx]);
+
ret = msm_pcie_get_resources(&msm_pcie_dev[rc_idx],
msm_pcie_dev[rc_idx].pdev);
@@ -6490,11 +6537,16 @@ int __init pcie_init(void)
static void __exit pcie_exit(void)
{
+ int i;
+
PCIE_GEN_DBG("pcie:%s.\n", __func__);
platform_driver_unregister(&msm_pcie_driver);
msm_pcie_debugfs_exit();
+
+ for (i = 0; i < MAX_RC_NUM; i++)
+ msm_pcie_sysfs_exit(&msm_pcie_dev[i]);
}
subsys_initcall_sync(pcie_init);
diff --git a/drivers/pinctrl/qcom/pinctrl-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpi.c
index 67cac25689ef..4ca5d5fa0531 100644
--- a/drivers/pinctrl/qcom/pinctrl-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-lpi.c
@@ -117,12 +117,12 @@ static const u32 lpi_offset[] = {
0x00005010,
0x00005020,
0x00005030,
- 0x00005040,
- 0x00005050,
0x00006000,
0x00006010,
0x00007000,
0x00007010,
+ 0x00005040,
+ 0x00005050,
0x00008000,
0x00008010,
0x00008020,
diff --git a/drivers/platform/goldfish/pdev_bus.c b/drivers/platform/goldfish/pdev_bus.c
index 1f52462f4cdd..dd9ea463c2a4 100644
--- a/drivers/platform/goldfish/pdev_bus.c
+++ b/drivers/platform/goldfish/pdev_bus.c
@@ -157,23 +157,26 @@ static int goldfish_new_pdev(void)
static irqreturn_t goldfish_pdev_bus_interrupt(int irq, void *dev_id)
{
irqreturn_t ret = IRQ_NONE;
+
while (1) {
u32 op = readl(pdev_bus_base + PDEV_BUS_OP);
- switch (op) {
- case PDEV_BUS_OP_DONE:
- return IRQ_NONE;
+ switch (op) {
case PDEV_BUS_OP_REMOVE_DEV:
goldfish_pdev_remove();
+ ret = IRQ_HANDLED;
break;
case PDEV_BUS_OP_ADD_DEV:
goldfish_new_pdev();
+ ret = IRQ_HANDLED;
break;
+
+ case PDEV_BUS_OP_DONE:
+ default:
+ return ret;
}
- ret = IRQ_HANDLED;
}
- return ret;
}
static int goldfish_pdev_bus_probe(struct platform_device *pdev)
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
index 985c3e560c86..d94e8f9f0e12 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1482,17 +1482,24 @@ void ipa_install_dflt_flt_rules(u32 ipa_ep_idx)
void ipa_delete_dflt_flt_rules(u32 ipa_ep_idx)
{
+ struct ipa_flt_tbl *tbl;
struct ipa_ep_context *ep = &ipa_ctx->ep[ipa_ep_idx];
mutex_lock(&ipa_ctx->lock);
if (ep->dflt_flt4_rule_hdl) {
+ tbl = &ipa_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v4];
__ipa_del_flt_rule(ep->dflt_flt4_rule_hdl);
ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v4);
+ /* Reset the sticky flag. */
+ tbl->sticky_rear = false;
ep->dflt_flt4_rule_hdl = 0;
}
if (ep->dflt_flt6_rule_hdl) {
+ tbl = &ipa_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v6];
__ipa_del_flt_rule(ep->dflt_flt6_rule_hdl);
ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v6);
+ /* Reset the sticky flag. */
+ tbl->sticky_rear = false;
ep->dflt_flt6_rule_hdl = 0;
}
mutex_unlock(&ipa_ctx->lock);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index aa681d3eacaa..5b706b6f493b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -2253,7 +2253,8 @@ static int ipa3_q6_set_ex_path_to_apps(void)
reg_write.pipeline_clear_options =
IPAHAL_HPS_CLEAR;
reg_write.offset =
- ipahal_get_reg_ofst(IPA_ENDP_STATUS_n);
+ ipahal_get_reg_n_ofst(IPA_ENDP_STATUS_n,
+ ep_idx);
ipahal_get_status_ep_valmask(
ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS),
&valmask);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
index 362294b0f695..41b29335d23b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
@@ -1389,16 +1389,23 @@ void ipa3_install_dflt_flt_rules(u32 ipa_ep_idx)
void ipa3_delete_dflt_flt_rules(u32 ipa_ep_idx)
{
struct ipa3_ep_context *ep = &ipa3_ctx->ep[ipa_ep_idx];
+ struct ipa3_flt_tbl *tbl;
mutex_lock(&ipa3_ctx->lock);
if (ep->dflt_flt4_rule_hdl) {
+ tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v4];
__ipa_del_flt_rule(ep->dflt_flt4_rule_hdl);
ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v4);
+ /* Reset the sticky flag. */
+ tbl->sticky_rear = false;
ep->dflt_flt4_rule_hdl = 0;
}
if (ep->dflt_flt6_rule_hdl) {
+ tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v6];
__ipa_del_flt_rule(ep->dflt_flt6_rule_hdl);
ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v6);
+ /* Reset the sticky flag. */
+ tbl->sticky_rear = false;
ep->dflt_flt6_rule_hdl = 0;
}
mutex_unlock(&ipa3_ctx->lock);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 2f28ba673d5a..c8ff06ddda87 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -3565,11 +3565,6 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl)
memset(&mem, 0, sizeof(mem));
- if (IPA_CLIENT_IS_PROD(ep->client)) {
- res = gsi_stop_channel(ep->gsi_chan_hdl);
- goto end_sequence;
- }
-
for (i = 0; i < IPA_GSI_CHANNEL_STOP_MAX_RETRY; i++) {
IPADBG("Calling gsi_stop_channel\n");
res = gsi_stop_channel(ep->gsi_chan_hdl);
@@ -3577,12 +3572,14 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl)
if (res != -GSI_STATUS_AGAIN && res != -GSI_STATUS_TIMED_OUT)
goto end_sequence;
- IPADBG("Inject a DMA_TASK with 1B packet to IPA and retry\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;
+ 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;
+ }
}
/* sleep for short period to flush IPA */
diff --git a/drivers/platform/msm/mhi/mhi.h b/drivers/platform/msm/mhi/mhi.h
index 4bce96102525..60e02fcb5e4b 100644
--- a/drivers/platform/msm/mhi/mhi.h
+++ b/drivers/platform/msm/mhi/mhi.h
@@ -95,9 +95,12 @@ struct bhi_ctxt_t {
u32 poll_timeout;
/* BHI/E vector table */
bool manage_boot; /* fw download done by MHI host */
+ bool support_rddm;
struct work_struct fw_load_work;
struct firmware_info firmware_info;
struct bhie_vec_table fw_table;
+ struct bhie_vec_table rddm_table;
+ size_t rddm_size;
};
enum MHI_CHAN_DIR {
@@ -140,12 +143,6 @@ enum MHI_CHAIN {
MHI_TRE_CHAIN_reserved = 0x80000000
};
-enum MHI_EVENT_RING_STATE {
- MHI_EVENT_RING_UINIT = 0x0,
- MHI_EVENT_RING_INIT = 0x1,
- MHI_EVENT_RING_reserved = 0x80000000
-};
-
enum MHI_STATE {
MHI_STATE_RESET = 0x0,
MHI_STATE_READY = 0x1,
@@ -154,9 +151,8 @@ enum MHI_STATE {
MHI_STATE_M2 = 0x4,
MHI_STATE_M3 = 0x5,
MHI_STATE_BHI = 0x7,
- MHI_STATE_SYS_ERR = 0x8,
- MHI_STATE_LIMIT = 0x9,
- MHI_STATE_reserved = 0x80000000
+ MHI_STATE_SYS_ERR = 0xFF,
+ MHI_STATE_LIMIT,
};
enum MHI_BRSTMODE {
@@ -168,22 +164,36 @@ enum MHI_BRSTMODE {
};
enum MHI_PM_STATE {
- MHI_PM_DISABLE = 0x0, /* MHI is not enabled */
- MHI_PM_POR = 0x1, /* Power On Reset State */
- MHI_PM_M0 = 0x2,
- MHI_PM_M1 = 0x4,
- MHI_PM_M1_M2_TRANSITION = 0x8, /* Register access not allowed */
- MHI_PM_M2 = 0x10,
- MHI_PM_M3_ENTER = 0x20,
- MHI_PM_M3 = 0x40,
- MHI_PM_M3_EXIT = 0x80,
+ MHI_PM_DISABLE = BIT(0), /* MHI is not enabled */
+ MHI_PM_POR = BIT(1), /* Power On Reset State */
+ MHI_PM_M0 = BIT(2),
+ MHI_PM_M1 = BIT(3),
+ MHI_PM_M1_M2_TRANSITION = BIT(4), /* Register access not allowed */
+ MHI_PM_M2 = BIT(5),
+ MHI_PM_M3_ENTER = BIT(6),
+ MHI_PM_M3 = BIT(7),
+ MHI_PM_M3_EXIT = BIT(8),
+ MHI_PM_SYS_ERR_DETECT = BIT(9),
+ MHI_PM_SYS_ERR_PROCESS = BIT(10),
+ MHI_PM_SHUTDOWN_PROCESS = BIT(11),
+ MHI_PM_LD_ERR_FATAL_DETECT = BIT(12), /* Link not accessible */
+ MHI_PM_SSR_PENDING = BIT(13)
+};
+
+struct mhi_pm_transitions {
+ enum MHI_PM_STATE from_state;
+ u32 to_states;
};
#define MHI_DB_ACCESS_VALID(pm_state) (pm_state & (MHI_PM_M0 | MHI_PM_M1))
#define MHI_WAKE_DB_ACCESS_VALID(pm_state) (pm_state & (MHI_PM_M0 | \
MHI_PM_M1 | MHI_PM_M2))
-#define MHI_REG_ACCESS_VALID(pm_state) ((pm_state > MHI_PM_DISABLE) && \
- (pm_state < MHI_PM_M3_EXIT))
+#define MHI_REG_ACCESS_VALID(pm_state) ((pm_state & (MHI_PM_POR | MHI_PM_M0 | \
+ MHI_PM_M1 | MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \
+ MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \
+ MHI_PM_SHUTDOWN_PROCESS)))
+#define MHI_EVENT_ACCESS_INVALID(pm_state) (pm_state == MHI_PM_DISABLE || \
+ pm_state >= MHI_PM_SYS_ERR_DETECT)
struct __packed mhi_event_ctxt {
u32 mhi_intmodt;
u32 mhi_event_er_type;
@@ -239,7 +249,6 @@ enum MHI_PKT_TYPE {
MHI_PKT_TYPE_TX_EVENT = 0x22,
MHI_PKT_TYPE_EE_EVENT = 0x40,
MHI_PKT_TYPE_STALE_EVENT, /* Internal event */
- MHI_PKT_TYPE_SYS_ERR_EVENT = 0xFF,
};
struct __packed mhi_tx_pkt {
@@ -393,7 +402,8 @@ enum STATE_TRANSITION {
STATE_TRANSITION_LINK_DOWN,
STATE_TRANSITION_WAKE,
STATE_TRANSITION_BHIE,
- STATE_TRANSITION_SYS_ERR,
+ STATE_TRANSITION_RDDM,
+ STATE_TRANSITION_SYS_ERR = MHI_STATE_SYS_ERR,
STATE_TRANSITION_MAX
};
@@ -402,7 +412,8 @@ enum MHI_EXEC_ENV {
MHI_EXEC_ENV_SBL = 0x1,
MHI_EXEC_ENV_AMSS = 0x2,
MHI_EXEC_ENV_BHIE = 0x3,
- MHI_EXEC_ENV_reserved = 0x80000000
+ MHI_EXEC_ENV_RDDM = 0x4,
+ MHI_EXEC_ENV_DISABLE_TRANSITION, /* local EE, not related to mhi spec */
};
struct mhi_chan_info {
@@ -480,7 +491,7 @@ struct mhi_counters {
};
struct mhi_flags {
- u32 mhi_initialized;
+ bool mhi_initialized;
u32 link_up;
bool bb_required;
};
@@ -546,6 +557,7 @@ struct mhi_device_ctxt {
struct mhi_event_ring_cfg *ev_ring_props;
struct work_struct st_thread_worker;
struct work_struct process_m1_worker;
+ struct work_struct process_sys_err_worker;
struct mhi_wait_queues mhi_ev_wq;
struct dev_mmio_info mmio_info;
@@ -587,7 +599,8 @@ struct mhi_device_ctxt {
void (*assert_wake)(struct mhi_device_ctxt *mhi_dev_ctxt,
bool force_set);
void (*deassert_wake)(struct mhi_device_ctxt *mhi_dev_ctxt);
-
+ void (*status_cb)(enum MHI_CB_REASON, void *priv);
+ void *priv_data; /* private data for bus master */
struct completion cmd_complete;
};
@@ -612,7 +625,6 @@ struct mhi_event_ring_cfg {
*/
u32 priority;
enum MHI_RING_CLASS class;
- enum MHI_EVENT_RING_STATE state;
irqreturn_t (*mhi_handler_ptr)(int , void *);
};
#define MHI_EV_PRIORITY_TASKLET (1)
@@ -673,13 +685,12 @@ enum MHI_EVENT_CCS get_cmd_pkt(struct mhi_device_ctxt *mhi_dev_ctxt,
union mhi_cmd_pkt **cmd_pkt, u32 event_index);
int parse_cmd_event(struct mhi_device_ctxt *ctxt,
union mhi_event_pkt *event, u32 event_index);
-int mhi_test_for_device_ready(
- struct mhi_device_ctxt *mhi_dev_ctxt);
-int mhi_test_for_device_reset(
- struct mhi_device_ctxt *mhi_dev_ctxt);
+int mhi_test_for_device_ready(struct mhi_device_ctxt *mhi_dev_ctxt);
+int mhi_test_for_device_reset(struct mhi_device_ctxt *mhi_dev_ctxt);
int validate_ring_el_addr(struct mhi_ring *ring, uintptr_t addr);
int validate_ev_el_addr(struct mhi_ring *ring, uintptr_t addr);
void mhi_state_change_worker(struct work_struct *work);
+void mhi_sys_err_worker(struct work_struct *work);
int mhi_init_state_transition(struct mhi_device_ctxt *mhi_dev_ctxt,
enum STATE_TRANSITION new_state);
int mhi_wait_for_mdm(struct mhi_device_ctxt *mhi_dev_ctxt);
@@ -709,7 +720,7 @@ int mhi_reg_notifiers(struct mhi_device_ctxt *mhi_dev_ctxt);
int mhi_cpu_notifier_cb(struct notifier_block *nfb, unsigned long action,
void *hcpu);
int init_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt);
-int mhi_turn_off_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt);
+int mhi_turn_off_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt, bool graceful);
int mhi_turn_on_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt);
int mhi_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt);
int mhi_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt);
@@ -757,5 +768,13 @@ void mhi_ev_task(unsigned long data);
void process_event_ring(struct work_struct *work);
int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt);
int process_m3_transition(struct mhi_device_ctxt *mhi_dev_ctxt);
+enum MHI_PM_STATE __must_check mhi_tryset_pm_state(struct mhi_device_ctxt *,
+ enum MHI_PM_STATE);
+void mhi_reset_chan(struct mhi_device_ctxt *mhi_dev_ctxt, int chan);
+void free_tre_ring(struct mhi_device_ctxt *mhi_dev_ctxt, int chan);
+void process_disable_transition(enum MHI_PM_STATE transition_state,
+ struct mhi_device_ctxt *mhi_dev_ctxt);
+bool mhi_in_sys_err(struct mhi_device_ctxt *mhi_dev_ctxt);
+void bhi_exit(struct mhi_device_ctxt *mhi_dev_ctxt);
#endif
diff --git a/drivers/platform/msm/mhi/mhi_bhi.c b/drivers/platform/msm/mhi/mhi_bhi.c
index 0cc8967757ec..3bc8205b5f0f 100644
--- a/drivers/platform/msm/mhi/mhi_bhi.c
+++ b/drivers/platform/msm/mhi/mhi_bhi.c
@@ -137,17 +137,36 @@ static int bhi_alloc_pbl_xfer(struct mhi_device_ctxt *mhi_dev_ctxt,
return 0;
}
-/* Load firmware via bhie protocol */
-static int bhi_load_bhie_firmware(struct mhi_device_ctxt *mhi_dev_ctxt)
+/* transfer firmware or ramdump via bhie protocol */
+static int bhi_bhie_transfer(struct mhi_device_ctxt *mhi_dev_ctxt,
+ struct bhie_vec_table *vec_table,
+ bool tx_vec_table)
{
struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt;
- struct bhie_vec_table *fw_table = &bhi_ctxt->fw_table;
+ /* last element is the vector table */
const struct bhie_mem_info *bhie_mem_info =
- &fw_table->bhie_mem_info[fw_table->segment_count - 1];
+ &vec_table->bhie_mem_info[vec_table->segment_count - 1];
u32 val;
- const u32 tx_sequence = fw_table->sequence++;
+ const u32 tx_sequence = vec_table->sequence++;
unsigned long timeout;
rwlock_t *pm_xfer_lock = &mhi_dev_ctxt->pm_xfer_lock;
+ unsigned bhie_vecaddr_high_offs, bhie_vecaddr_low_offs,
+ bhie_vecsize_offs, bhie_vecdb_offs,
+ bhie_vecstatus_offs;
+
+ if (tx_vec_table) {
+ bhie_vecaddr_high_offs = BHIE_TXVECADDR_HIGH_OFFS;
+ bhie_vecaddr_low_offs = BHIE_TXVECADDR_LOW_OFFS;
+ bhie_vecsize_offs = BHIE_TXVECSIZE_OFFS;
+ bhie_vecdb_offs = BHIE_TXVECDB_OFFS;
+ bhie_vecstatus_offs = BHIE_TXVECSTATUS_OFFS;
+ } else {
+ bhie_vecaddr_high_offs = BHIE_RXVECADDR_HIGH_OFFS;
+ bhie_vecaddr_low_offs = BHIE_RXVECADDR_LOW_OFFS;
+ bhie_vecsize_offs = BHIE_RXVECSIZE_OFFS;
+ bhie_vecdb_offs = BHIE_RXVECDB_OFFS;
+ bhie_vecstatus_offs = BHIE_RXVECSTATUS_OFFS;
+ }
/* Program TX/RX Vector table */
read_lock_bh(pm_xfer_lock);
@@ -157,27 +176,17 @@ static int bhi_load_bhie_firmware(struct mhi_device_ctxt *mhi_dev_ctxt)
}
val = HIGH_WORD(bhie_mem_info->phys_addr);
- mhi_reg_write(mhi_dev_ctxt,
- bhi_ctxt->bhi_base,
- BHIE_TXVECADDR_HIGH_OFFS,
- val);
+ mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base,
+ bhie_vecaddr_high_offs, val);
val = LOW_WORD(bhie_mem_info->phys_addr);
- mhi_reg_write(mhi_dev_ctxt,
- bhi_ctxt->bhi_base,
- BHIE_TXVECADDR_LOW_OFFS,
- val);
+ mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base,
+ bhie_vecaddr_low_offs, val);
val = (u32)bhie_mem_info->size;
- mhi_reg_write(mhi_dev_ctxt,
- bhi_ctxt->bhi_base,
- BHIE_TXVECSIZE_OFFS,
- val);
+ mhi_reg_write(mhi_dev_ctxt, bhi_ctxt->bhi_base, bhie_vecsize_offs, val);
/* Ring DB to begin Xfer */
- mhi_reg_write_field(mhi_dev_ctxt,
- bhi_ctxt->bhi_base,
- BHIE_TXVECDB_OFFS,
- BHIE_TXVECDB_SEQNUM_BMSK,
- BHIE_TXVECDB_SEQNUM_SHFT,
+ mhi_reg_write_field(mhi_dev_ctxt, bhi_ctxt->bhi_base, bhie_vecdb_offs,
+ BHIE_TXVECDB_SEQNUM_BMSK, BHIE_TXVECDB_SEQNUM_SHFT,
tx_sequence);
read_unlock_bh(pm_xfer_lock);
@@ -190,10 +199,10 @@ static int bhi_load_bhie_firmware(struct mhi_device_ctxt *mhi_dev_ctxt)
read_unlock_bh(pm_xfer_lock);
return -EIO;
}
- val = mhi_reg_read(bhi_ctxt->bhi_base, BHIE_TXVECSTATUS_OFFS);
+ val = mhi_reg_read(bhi_ctxt->bhi_base, bhie_vecstatus_offs);
read_unlock_bh(pm_xfer_lock);
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "TXVEC_STATUS:0x%x\n", val);
+ "%sVEC_STATUS:0x%x\n", tx_vec_table ? "TX" : "RX", val);
current_seq = (val & BHIE_TXVECSTATUS_SEQNUM_BMSK) >>
BHIE_TXVECSTATUS_SEQNUM_SHFT;
status = (val & BHIE_TXVECSTATUS_STATUS_BMSK) >>
@@ -201,17 +210,60 @@ static int bhi_load_bhie_firmware(struct mhi_device_ctxt *mhi_dev_ctxt)
if ((status == BHIE_TXVECSTATUS_STATUS_XFER_COMPL) &&
(current_seq == tx_sequence)) {
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Image transfer complete\n");
+ "%s transfer complete\n",
+ tx_vec_table ? "image" : "rddm");
return 0;
}
msleep(BHI_POLL_SLEEP_TIME_MS);
}
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
- "Error xfering image via BHIE\n");
+ "Error xfer %s via BHIE\n", tx_vec_table ? "image" : "rddm");
return -EIO;
}
+static int bhi_rddm_graceful(struct mhi_device_ctxt *mhi_dev_ctxt)
+{
+ int ret;
+ struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt;
+ struct bhie_vec_table *rddm_table = &bhi_ctxt->rddm_table;
+ enum MHI_EXEC_ENV exec_env = mhi_dev_ctxt->dev_exec_env;
+
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Entered with pm_state:0x%x exec_env:0x%x mhi_state:%s\n",
+ mhi_dev_ctxt->mhi_pm_state, exec_env,
+ TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
+
+ if (exec_env != MHI_EXEC_ENV_RDDM) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Not in RDDM exec env, exec_env:0x%x\n", exec_env);
+ return -EIO;
+ }
+
+ ret = bhi_bhie_transfer(mhi_dev_ctxt, rddm_table, false);
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "rddm transfer status:%d\n", ret);
+ return ret;
+}
+
+/* collect ramdump from device using bhie protocol */
+int bhi_rddm(struct mhi_device_ctxt *mhi_dev_ctxt, bool in_panic)
+{
+ struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt;
+ struct bhie_vec_table *rddm_table = &bhi_ctxt->rddm_table;
+
+ if (!rddm_table->bhie_mem_info) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "RDDM table == NULL\n");
+ return -ENOMEM;
+ }
+
+ if (!in_panic)
+ return bhi_rddm_graceful(mhi_dev_ctxt);
+
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "RDDM collection in panic not yet supported\n");
+ return -EINVAL;
+}
+
static int bhi_load_firmware(struct mhi_device_ctxt *mhi_dev_ctxt)
{
struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt;
@@ -425,7 +477,8 @@ void bhi_firmware_download(struct work_struct *work)
return;
}
- ret = bhi_load_bhie_firmware(mhi_dev_ctxt);
+ ret = bhi_bhie_transfer(mhi_dev_ctxt, &mhi_dev_ctxt->bhi_ctxt.fw_table,
+ true);
if (ret) {
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
"Failed to Load amss firmware\n");
@@ -437,6 +490,7 @@ int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt)
struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt;
struct firmware_info *fw_info = &bhi_ctxt->firmware_info;
struct bhie_vec_table *fw_table = &bhi_ctxt->fw_table;
+ struct bhie_vec_table *rddm_table = &bhi_ctxt->rddm_table;
const struct firmware *firmware;
struct scatterlist *itr;
int ret, i;
@@ -503,7 +557,75 @@ int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt)
fw_table->sequence++;
release_firmware(firmware);
+ /* allocate memory and setup rddm table */
+ if (bhi_ctxt->support_rddm) {
+ ret = bhi_alloc_bhie_xfer(mhi_dev_ctxt, bhi_ctxt->rddm_size,
+ rddm_table);
+ if (!ret) {
+ for (i = 0, itr = &rddm_table->sg_list[1];
+ i < rddm_table->segment_count - 1; i++, itr++) {
+ size_t size = rddm_table->bhie_mem_info[i].size;
+
+ rddm_table->bhi_vec_entry[i].phys_addr =
+ rddm_table->bhie_mem_info[i].phys_addr;
+ rddm_table->bhi_vec_entry[i].size = size;
+ sg_set_buf(itr, rddm_table->
+ bhie_mem_info[i].aligned, size);
+ sg_dma_address(itr) =
+ rddm_table->bhie_mem_info[i].phys_addr;
+ sg_dma_len(itr) = size;
+ }
+ rddm_table->sequence++;
+ } else {
+ /* out of memory for rddm, not fatal error */
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Could not successfully allocate mem for rddm\n");
+ }
+ }
+
/* Schedule a worker thread and wait for BHI Event */
schedule_work(&bhi_ctxt->fw_load_work);
return 0;
}
+
+void bhi_exit(struct mhi_device_ctxt *mhi_dev_ctxt)
+{
+ struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt;
+ struct bhie_vec_table *fw_table = &bhi_ctxt->fw_table;
+ struct bhie_vec_table *rddm_table = &bhi_ctxt->rddm_table;
+ struct device *dev = &mhi_dev_ctxt->plat_dev->dev;
+ struct bhie_mem_info *bhie_mem_info;
+ int i;
+
+ if (bhi_ctxt->manage_boot == false)
+ return;
+
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "freeing firmware and rddm memory\n");
+
+ /* free memory allocated for firmware */
+ kfree(fw_table->sg_list);
+ fw_table->sg_list = NULL;
+ bhie_mem_info = fw_table->bhie_mem_info;
+ for (i = 0; i < fw_table->segment_count; i++, bhie_mem_info++)
+ dma_free_coherent(dev, bhie_mem_info->alloc_size,
+ bhie_mem_info->pre_aligned,
+ bhie_mem_info->dma_handle);
+ fw_table->bhie_mem_info = NULL;
+ /* vector table is the last entry in bhie_mem_info */
+ fw_table->bhi_vec_entry = NULL;
+
+ if (!rddm_table->bhie_mem_info)
+ return;
+
+ /* free memory allocated for rddm */
+ kfree(rddm_table->sg_list);
+ rddm_table->sg_list = NULL;
+ bhie_mem_info = rddm_table->bhie_mem_info;
+ for (i = 0; i < rddm_table->segment_count; i++, bhie_mem_info++)
+ dma_free_coherent(dev, bhie_mem_info->alloc_size,
+ bhie_mem_info->pre_aligned,
+ bhie_mem_info->dma_handle);
+ rddm_table->bhie_mem_info = NULL;
+ rddm_table->bhi_vec_entry = NULL;
+}
diff --git a/drivers/platform/msm/mhi/mhi_bhi.h b/drivers/platform/msm/mhi/mhi_bhi.h
index 15137ba5dfdf..8f7b3d69347c 100644
--- a/drivers/platform/msm/mhi/mhi_bhi.h
+++ b/drivers/platform/msm/mhi/mhi_bhi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 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
@@ -90,5 +90,6 @@
int bhi_probe(struct mhi_device_ctxt *mhi_dev_ctxt);
void bhi_firmware_download(struct work_struct *work);
+int bhi_rddm(struct mhi_device_ctxt *mhi_dev_ctxt, bool in_panic);
#endif
diff --git a/drivers/platform/msm/mhi/mhi_event.c b/drivers/platform/msm/mhi/mhi_event.c
index ae677bae63dc..ea324339eac7 100644
--- a/drivers/platform/msm/mhi/mhi_event.c
+++ b/drivers/platform/msm/mhi/mhi_event.c
@@ -226,8 +226,7 @@ int init_local_ev_ring_by_type(struct mhi_device_ctxt *mhi_dev_ctxt,
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n");
for (i = 0; i < mhi_dev_ctxt->mmio_info.nr_event_rings; i++) {
if (GET_EV_PROPS(EV_TYPE,
- mhi_dev_ctxt->ev_ring_props[i].flags) == type &&
- !mhi_dev_ctxt->ev_ring_props[i].state) {
+ mhi_dev_ctxt->ev_ring_props[i].flags) == type) {
ret_val = mhi_init_local_event_ring(mhi_dev_ctxt,
mhi_dev_ctxt->ev_ring_props[i].nr_desc,
i);
@@ -292,7 +291,6 @@ int mhi_init_local_event_ring(struct mhi_device_ctxt *mhi_dev_ctxt,
break;
}
}
- mhi_dev_ctxt->ev_ring_props[ring_index].state = MHI_EVENT_RING_INIT;
spin_unlock_irqrestore(lock, flags);
return ret_val;
}
@@ -309,6 +307,7 @@ void mhi_reset_ev_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt,
&mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[index];
local_ev_ctxt =
&mhi_dev_ctxt->mhi_local_event_ctxt[index];
+ spin_lock_irq(&local_ev_ctxt->ring_lock);
ev_ctxt->mhi_event_read_ptr = ev_ctxt->mhi_event_ring_base_addr;
ev_ctxt->mhi_event_write_ptr = ev_ctxt->mhi_event_ring_base_addr;
local_ev_ctxt->rp = local_ev_ctxt->base;
@@ -317,6 +316,5 @@ void mhi_reset_ev_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt,
ev_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.ec_list[index];
ev_ctxt->mhi_event_read_ptr = ev_ctxt->mhi_event_ring_base_addr;
ev_ctxt->mhi_event_write_ptr = ev_ctxt->mhi_event_ring_base_addr;
- /* Flush writes to MMIO */
- wmb();
+ spin_unlock_irq(&local_ev_ctxt->ring_lock);
}
diff --git a/drivers/platform/msm/mhi/mhi_iface.c b/drivers/platform/msm/mhi/mhi_iface.c
index f1c562974816..64a09a2f9fbb 100644
--- a/drivers/platform/msm/mhi/mhi_iface.c
+++ b/drivers/platform/msm/mhi/mhi_iface.c
@@ -189,6 +189,7 @@ static int mhi_pci_probe(struct pci_dev *pcie_device,
mhi_dev_ctxt->mhi_pm_state = MHI_PM_DISABLE;
INIT_WORK(&mhi_dev_ctxt->process_m1_worker, process_m1_transition);
INIT_WORK(&mhi_dev_ctxt->st_thread_worker, mhi_state_change_worker);
+ INIT_WORK(&mhi_dev_ctxt->process_sys_err_worker, mhi_sys_err_worker);
mutex_init(&mhi_dev_ctxt->pm_lock);
rwlock_init(&mhi_dev_ctxt->pm_xfer_lock);
spin_lock_init(&mhi_dev_ctxt->dev_wake_lock);
diff --git a/drivers/platform/msm/mhi/mhi_isr.c b/drivers/platform/msm/mhi/mhi_isr.c
index 9aa9aeb7e646..70e4393f2f59 100644
--- a/drivers/platform/msm/mhi/mhi_isr.c
+++ b/drivers/platform/msm/mhi/mhi_isr.c
@@ -23,16 +23,18 @@ static int mhi_process_event_ring(
union mhi_event_pkt *local_rp = NULL;
union mhi_event_pkt *device_rp = NULL;
union mhi_event_pkt event_to_process;
- int ret_val = 0;
+ int count = 0;
struct mhi_event_ctxt *ev_ctxt = NULL;
unsigned long flags;
struct mhi_ring *local_ev_ctxt =
&mhi_dev_ctxt->mhi_local_event_ctxt[ev_index];
- mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "enter ev_index:%u\n", ev_index);
+ mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Enter ev_index:%u\n", ev_index);
read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock);
- if (unlikely(mhi_dev_ctxt->mhi_pm_state == MHI_PM_DISABLE)) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR, "Invalid MHI PM State\n");
+ if (unlikely(MHI_EVENT_ACCESS_INVALID(mhi_dev_ctxt->mhi_pm_state))) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "No event access, PM_STATE:0x%x\n",
+ mhi_dev_ctxt->mhi_pm_state);
read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
return -EIO;
}
@@ -98,6 +100,7 @@ static int mhi_process_event_ring(
{
u32 chan;
struct mhi_ring *ring;
+ unsigned long flags;
__pm_stay_awake(&mhi_dev_ctxt->w_lock);
chan = MHI_EV_READ_CHID(EV_CHID, &event_to_process);
@@ -107,12 +110,12 @@ static int mhi_process_event_ring(
break;
}
ring = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
- spin_lock_bh(&ring->ring_lock);
+ spin_lock_irqsave(&ring->ring_lock, flags);
if (ring->ch_state == MHI_CHAN_STATE_ENABLED)
parse_xfer_event(mhi_dev_ctxt,
&event_to_process,
ev_index);
- spin_unlock_bh(&ring->ring_lock);
+ spin_unlock_irqrestore(&ring->ring_lock, flags);
__pm_relax(&mhi_dev_ctxt->w_lock);
event_quota--;
break;
@@ -136,18 +139,41 @@ static int mhi_process_event_ring(
mhi_dev_ctxt->mhi_state =
mhi_get_m_state(mhi_dev_ctxt);
if (mhi_dev_ctxt->mhi_state == MHI_STATE_M1) {
- mhi_dev_ctxt->mhi_pm_state = MHI_PM_M1;
- mhi_dev_ctxt->counters.m0_m1++;
- schedule_work(&mhi_dev_ctxt->
- process_m1_worker);
+ enum MHI_PM_STATE state;
+
+ state = mhi_tryset_pm_state
+ (mhi_dev_ctxt, MHI_PM_M1);
+ if (state == MHI_PM_M1) {
+ mhi_dev_ctxt->counters.m0_m1++;
+ schedule_work
+ (&mhi_dev_ctxt->
+ process_m1_worker);
+ }
}
write_unlock_irqrestore(&mhi_dev_ctxt->
- pm_xfer_lock,
- flags);
+ pm_xfer_lock, flags);
break;
case STATE_TRANSITION_M3:
process_m3_transition(mhi_dev_ctxt);
break;
+ case STATE_TRANSITION_SYS_ERR:
+ {
+ enum MHI_PM_STATE new_state;
+ unsigned long flags;
+
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "MHI System Error Detected\n");
+ write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock,
+ flags);
+ new_state = mhi_tryset_pm_state
+ (mhi_dev_ctxt, MHI_PM_SYS_ERR_DETECT);
+ write_unlock_irqrestore
+ (&mhi_dev_ctxt->pm_xfer_lock, flags);
+ if (new_state == MHI_PM_SYS_ERR_DETECT)
+ schedule_work(&mhi_dev_ctxt->
+ process_sys_err_worker);
+ break;
+ }
default:
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
"Unsupported STE received ring 0x%x State:%s\n",
@@ -158,28 +184,36 @@ static int mhi_process_event_ring(
}
case MHI_PKT_TYPE_EE_EVENT:
{
- enum STATE_TRANSITION new_state;
+ enum STATE_TRANSITION new_state = 0;
+ enum MHI_EXEC_ENV event =
+ MHI_READ_EXEC_ENV(&event_to_process);
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "MHI EEE received ring 0x%x\n", ev_index);
+ "MHI EE received ring 0x%x event:0x%x\n",
+ ev_index, event);
__pm_stay_awake(&mhi_dev_ctxt->w_lock);
__pm_relax(&mhi_dev_ctxt->w_lock);
- switch (MHI_READ_EXEC_ENV(&event_to_process)) {
+ switch (event) {
case MHI_EXEC_ENV_SBL:
new_state = STATE_TRANSITION_SBL;
- mhi_init_state_transition(mhi_dev_ctxt,
- new_state);
break;
case MHI_EXEC_ENV_AMSS:
new_state = STATE_TRANSITION_AMSS;
- mhi_init_state_transition(mhi_dev_ctxt,
- new_state);
break;
case MHI_EXEC_ENV_BHIE:
new_state = STATE_TRANSITION_BHIE;
+ break;
+ case MHI_EXEC_ENV_RDDM:
+ new_state = STATE_TRANSITION_RDDM;
+ break;
+ default:
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Invalid EE Event 0x%x received\n",
+ event);
+ }
+ if (new_state)
mhi_init_state_transition(mhi_dev_ctxt,
new_state);
- }
break;
}
case MHI_PKT_TYPE_STALE_EVENT:
@@ -187,11 +221,6 @@ static int mhi_process_event_ring(
"Stale Event received for chan:%u\n",
MHI_EV_READ_CHID(EV_CHID, local_rp));
break;
- case MHI_PKT_TYPE_SYS_ERR_EVENT:
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "MHI System Error Detected. Triggering Reset\n");
- BUG();
- break;
default:
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
"Unsupported packet type code 0x%x\n",
@@ -207,13 +236,13 @@ static int mhi_process_event_ring(
ev_index,
ev_ctxt->mhi_event_read_ptr);
spin_unlock_irqrestore(&local_ev_ctxt->ring_lock, flags);
- ret_val = 0;
+ count++;
}
read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock);
mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt);
read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "exit ev_index:%u\n", ev_index);
- return ret_val;
+ return count;
}
void mhi_ev_task(unsigned long data)
@@ -222,10 +251,40 @@ void mhi_ev_task(unsigned long data)
struct mhi_device_ctxt *mhi_dev_ctxt =
mhi_ring->mhi_dev_ctxt;
int ev_index = mhi_ring->index;
+ const int CTRL_EV = 0; /* event ring for ctrl events */
+ int ret;
mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Enter\n");
+
/* Process event ring */
- mhi_process_event_ring(mhi_dev_ctxt, ev_index, U32_MAX);
+ ret = mhi_process_event_ring(mhi_dev_ctxt, ev_index, U32_MAX);
+ /*
+ * If we received MSI for primary event ring with no events to process
+ * check status register to see if device enter SYSERR status
+ */
+ if (ev_index == CTRL_EV && !ret) {
+ bool in_sys_err = false;
+ unsigned long flags;
+ enum MHI_PM_STATE new_state;
+
+ read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock);
+ if (MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state))
+ in_sys_err = mhi_in_sys_err(mhi_dev_ctxt);
+ read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
+
+ if (in_sys_err) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "MHI System Error Detected\n");
+ write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags);
+ new_state = mhi_tryset_pm_state(mhi_dev_ctxt,
+ MHI_PM_SYS_ERR_DETECT);
+ write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock,
+ flags);
+ if (new_state == MHI_PM_SYS_ERR_DETECT)
+ schedule_work(&mhi_dev_ctxt->
+ process_sys_err_worker);
+ }
+ }
enable_irq(MSI_TO_IRQ(mhi_dev_ctxt, ev_index));
mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE, "Exit\n");
@@ -258,7 +317,7 @@ struct mhi_result *mhi_poll(struct mhi_client_handle *client_handle)
ret_val = mhi_process_event_ring(client_config->mhi_dev_ctxt,
client_config->event_ring_index,
1);
- if (ret_val)
+ if (ret_val < 0)
mhi_log(client_config->mhi_dev_ctxt, MHI_MSG_INFO,
"NAPI failed to process event ring\n");
return &(client_config->result);
diff --git a/drivers/platform/msm/mhi/mhi_main.c b/drivers/platform/msm/mhi/mhi_main.c
index 644004672cd2..46baf7332900 100644
--- a/drivers/platform/msm/mhi/mhi_main.c
+++ b/drivers/platform/msm/mhi/mhi_main.c
@@ -30,11 +30,6 @@
#include "mhi_bhi.h"
#include "mhi_trace.h"
-static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,
- union mhi_cmd_pkt *cmd_pkt);
-static void disable_bb_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt,
- struct mhi_ring *bb_ctxt);
-
static int enable_bb_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt,
struct mhi_ring *bb_ctxt,
int nr_el,
@@ -306,6 +301,47 @@ static int populate_tre_ring(struct mhi_client_config *client_config)
return 0;
}
+void mhi_notify_client(struct mhi_client_handle *client_handle,
+ enum MHI_CB_REASON reason)
+{
+ struct mhi_cb_info cb_info = {0};
+ struct mhi_result result = {0};
+ struct mhi_client_config *client_config;
+
+ cb_info.result = NULL;
+ cb_info.cb_reason = reason;
+
+ if (client_handle == NULL)
+ return;
+
+ client_config = client_handle->client_config;
+
+ if (client_config->client_info.mhi_client_cb) {
+ result.user_data = client_config->user_data;
+ cb_info.chan = client_config->chan_info.chan_nr;
+ cb_info.result = &result;
+ mhi_log(client_config->mhi_dev_ctxt, MHI_MSG_INFO,
+ "Calling back for chan %d, reason %d\n",
+ cb_info.chan,
+ reason);
+ client_config->client_info.mhi_client_cb(&cb_info);
+ }
+}
+
+void mhi_notify_clients(struct mhi_device_ctxt *mhi_dev_ctxt,
+ enum MHI_CB_REASON reason)
+{
+ int i;
+ struct mhi_client_handle *client_handle = NULL;
+
+ for (i = 0; i < MHI_MAX_CHANNELS; ++i) {
+ if (VALID_CHAN_NR(i)) {
+ client_handle = mhi_dev_ctxt->client_handle_list[i];
+ mhi_notify_client(client_handle, reason);
+ }
+ }
+}
+
int mhi_open_channel(struct mhi_client_handle *client_handle)
{
int ret_val = 0;
@@ -389,10 +425,10 @@ int mhi_open_channel(struct mhi_client_handle *client_handle)
ret_val = 0;
}
- spin_lock(&cfg->event_lock);
+ spin_lock_irq(&cfg->event_lock);
cmd_event_pkt = cfg->cmd_event_pkt;
cmd_pkt = cfg->cmd_pkt;
- spin_unlock(&cfg->event_lock);
+ spin_unlock_irq(&cfg->event_lock);
ev_code = MHI_EV_READ_CODE(EV_TRB_CODE,
((union mhi_event_pkt *)&cmd_event_pkt));
@@ -628,10 +664,7 @@ void mhi_close_channel(struct mhi_client_handle *client_handle)
}
error_completion:
- ret_val = reset_chan_cmd(mhi_dev_ctxt, &cmd_pkt);
- if (ret_val)
- mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
- "Error resetting cmd ret:%d\n", ret_val);
+ mhi_reset_chan(mhi_dev_ctxt, chan);
read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock);
mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt);
@@ -1391,11 +1424,8 @@ int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt,
}
-static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,
- union mhi_cmd_pkt *cmd_pkt)
+void mhi_reset_chan(struct mhi_device_ctxt *mhi_dev_ctxt, int chan)
{
- u32 chan = 0;
- int ret_val = 0;
struct mhi_ring *local_chan_ctxt;
struct mhi_ring *ev_ring;
struct mhi_chan_ctxt *chan_ctxt;
@@ -1405,14 +1435,6 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,
union mhi_event_pkt *local_rp = NULL;
union mhi_event_pkt *device_rp = NULL;
- MHI_TRB_GET_INFO(CMD_TRB_CHID, cmd_pkt, chan);
-
- if (!VALID_CHAN_NR(chan)) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
- "Bad channel number for CCE\n");
- return -EINVAL;
- }
-
local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
chan_ctxt = &mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan];
ev_ring = &mhi_dev_ctxt->
@@ -1420,7 +1442,7 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,
ev_ctxt = &mhi_dev_ctxt->
dev_space.ring_ctxt.ec_list[chan_ctxt->mhi_event_ring_index];
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Processed cmd reset event\n");
+ "Marking all events for chan:%d as stale\n", chan);
/* Clear all stale events related to Channel */
spin_lock_irqsave(&ev_ring->ring_lock, flags);
@@ -1483,7 +1505,6 @@ static int reset_chan_cmd(struct mhi_device_ctxt *mhi_dev_ctxt,
chan_ctxt->mhi_trb_write_ptr = chan_ctxt->mhi_trb_ring_base_addr;
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Reset complete.\n");
- return ret_val;
}
enum MHI_EVENT_CCS get_cmd_pkt(struct mhi_device_ctxt *mhi_dev_ctxt,
@@ -1510,11 +1531,11 @@ int mhi_poll_inbound(struct mhi_client_handle *client_handle,
struct mhi_tx_pkt *pending_trb = 0;
struct mhi_device_ctxt *mhi_dev_ctxt = NULL;
struct mhi_ring *local_chan_ctxt = NULL;
- struct mhi_chan_cfg *cfg;
struct mhi_ring *bb_ctxt = NULL;
struct mhi_buf_info *bb = NULL;
struct mhi_client_config *client_config;
- int chan = 0, r = 0;
+ int chan = 0, r = -EIO;
+ unsigned long flags;
if (!client_handle || !result)
return -EINVAL;
@@ -1525,36 +1546,38 @@ int mhi_poll_inbound(struct mhi_client_handle *client_handle,
chan = client_config->chan_info.chan_nr;
local_chan_ctxt = &mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
- cfg = &mhi_dev_ctxt->mhi_chan_cfg[chan];
bb_ctxt = &mhi_dev_ctxt->chan_bb_list[chan];
- mutex_lock(&cfg->chan_lock);
- if (bb_ctxt->rp != bb_ctxt->ack_rp) {
- pending_trb = (struct mhi_tx_pkt *)(local_chan_ctxt->ack_rp);
- result->flags = pending_trb->info;
- bb = bb_ctxt->ack_rp;
- if (bb->bb_active) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE,
- "Bounce buffer active chan %d, copying data\n",
- chan);
+ spin_lock_irqsave(&local_chan_ctxt->ring_lock, flags);
+ if (local_chan_ctxt->ch_state == MHI_CHAN_STATE_ENABLED) {
+ if (bb_ctxt->rp != bb_ctxt->ack_rp) {
+ pending_trb =
+ (struct mhi_tx_pkt *)(local_chan_ctxt->ack_rp);
+ result->flags = pending_trb->info;
+ bb = bb_ctxt->ack_rp;
+ if (bb->bb_active) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE,
+ "Bounce buffer active chan %d, copying data\n",
+ chan);
+ }
+ result->buf_addr = bb->client_buf;
+ result->bytes_xferd = bb->filled_size;
+ result->transaction_status = 0;
+ r = delete_element(local_chan_ctxt,
+ &local_chan_ctxt->ack_rp,
+ &local_chan_ctxt->rp, NULL);
+ WARN_ON(r);
+ r = delete_element(bb_ctxt,
+ &bb_ctxt->ack_rp,
+ &bb_ctxt->rp, NULL);
+ WARN_ON(r);
+ } else {
+ result->buf_addr = 0;
+ result->bytes_xferd = 0;
+ r = -ENODATA;
}
- result->buf_addr = bb->client_buf;
- result->bytes_xferd = bb->filled_size;
- result->transaction_status = 0;
- r = delete_element(local_chan_ctxt,
- &local_chan_ctxt->ack_rp,
- &local_chan_ctxt->rp, NULL);
- BUG_ON(r);
- r = delete_element(bb_ctxt,
- &bb_ctxt->ack_rp,
- &bb_ctxt->rp, NULL);
- BUG_ON(r);
- } else {
- result->buf_addr = 0;
- result->bytes_xferd = 0;
- r = -ENODATA;
}
- mutex_unlock(&cfg->chan_lock);
+ spin_unlock_irqrestore(&local_chan_ctxt->ring_lock, flags);
mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE,
"Exited Result: Buf addr: 0x%p Bytes xfed 0x%zx chan %d\n",
result->buf_addr, result->bytes_xferd, chan);
@@ -1647,9 +1670,10 @@ void mhi_assert_device_wake(struct mhi_device_ctxt *mhi_dev_ctxt,
if (unlikely(force_set)) {
spin_lock_irqsave(&mhi_dev_ctxt->dev_wake_lock, flags);
atomic_inc(&mhi_dev_ctxt->counters.device_wake);
- mhi_write_db(mhi_dev_ctxt,
- mhi_dev_ctxt->mmio_info.chan_db_addr,
- MHI_DEV_WAKE_DB, 1);
+ if (MHI_WAKE_DB_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state))
+ mhi_write_db(mhi_dev_ctxt,
+ mhi_dev_ctxt->mmio_info.chan_db_addr,
+ MHI_DEV_WAKE_DB, 1);
spin_unlock_irqrestore(&mhi_dev_ctxt->dev_wake_lock, flags);
} else {
if (likely(atomic_add_unless(&mhi_dev_ctxt->
@@ -1744,7 +1768,7 @@ EXPORT_SYMBOL(mhi_deregister_channel);
int mhi_register_device(struct mhi_device *mhi_device,
const char *node_name,
- unsigned long user_data)
+ void *user_data)
{
const struct device_node *of_node;
struct mhi_device_ctxt *mhi_dev_ctxt = NULL, *itr;
@@ -1793,6 +1817,7 @@ int mhi_register_device(struct mhi_device *mhi_device,
mhi_dev_ctxt->mhi_pm_state = MHI_PM_DISABLE;
INIT_WORK(&mhi_dev_ctxt->process_m1_worker, process_m1_transition);
INIT_WORK(&mhi_dev_ctxt->st_thread_worker, mhi_state_change_worker);
+ INIT_WORK(&mhi_dev_ctxt->process_sys_err_worker, mhi_sys_err_worker);
mutex_init(&mhi_dev_ctxt->pm_lock);
rwlock_init(&mhi_dev_ctxt->pm_xfer_lock);
spin_lock_init(&mhi_dev_ctxt->dev_wake_lock);
@@ -1828,11 +1853,15 @@ int mhi_register_device(struct mhi_device *mhi_device,
if (!core_info->bar0_base || !core_info->irq_base)
return -EINVAL;
+ if (mhi_device->support_rddm && !mhi_device->rddm_size)
+ return -EINVAL;
mhi_dev_ctxt->bus_master_rt_get = mhi_device->pm_runtime_get;
- mhi_dev_ctxt->bus_master_rt_put = mhi_device->pm_runtime_noidle;
- if (!mhi_dev_ctxt->bus_master_rt_get ||
- !mhi_dev_ctxt->bus_master_rt_put)
+ mhi_dev_ctxt->bus_master_rt_put = mhi_device->pm_runtime_put_noidle;
+ mhi_dev_ctxt->status_cb = mhi_device->status_cb;
+ mhi_dev_ctxt->priv_data = user_data;
+ if (!mhi_dev_ctxt->bus_master_rt_get || !mhi_dev_ctxt->bus_master_rt_put
+ || !mhi_dev_ctxt->status_cb)
return -EINVAL;
ret = mhi_ctxt_init(mhi_dev_ctxt);
@@ -1849,12 +1878,44 @@ int mhi_register_device(struct mhi_device *mhi_device,
mhi_dev_ctxt->runtime_get = mhi_slave_mode_runtime_get;
mhi_dev_ctxt->runtime_put = mhi_slave_mode_runtime_put;
mhi_device->mhi_dev_ctxt = mhi_dev_ctxt;
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exit success\n");
+ /* Store RDDM information */
+ if (mhi_device->support_rddm) {
+ mhi_dev_ctxt->bhi_ctxt.support_rddm = true;
+ mhi_dev_ctxt->bhi_ctxt.rddm_size = mhi_device->rddm_size;
+
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Device support rddm of size:0x%lx bytes\n",
+ mhi_dev_ctxt->bhi_ctxt.rddm_size);
+ }
+
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exit success\n");
return 0;
}
EXPORT_SYMBOL(mhi_register_device);
+int mhi_xfer_rddm(struct mhi_device *mhi_device, enum mhi_rddm_segment seg,
+ struct scatterlist **sg_list)
+{
+ struct mhi_device_ctxt *mhi_dev_ctxt = mhi_device->mhi_dev_ctxt;
+ struct bhi_ctxt_t *bhi_ctxt = &mhi_dev_ctxt->bhi_ctxt;
+ int segments = 0;
+
+ *sg_list = NULL;
+ switch (seg) {
+ case MHI_RDDM_FW_SEGMENT:
+ *sg_list = bhi_ctxt->fw_table.sg_list;
+ segments = bhi_ctxt->fw_table.segment_count;
+ break;
+ case MHI_RDDM_RD_SEGMENT:
+ *sg_list = bhi_ctxt->rddm_table.sg_list;
+ segments = bhi_ctxt->rddm_table.segment_count;
+ break;
+ }
+ return segments;
+}
+EXPORT_SYMBOL(mhi_xfer_rddm);
+
void mhi_process_db_brstmode(struct mhi_device_ctxt *mhi_dev_ctxt,
void __iomem *io_addr,
uintptr_t chan,
diff --git a/drivers/platform/msm/mhi/mhi_pm.c b/drivers/platform/msm/mhi/mhi_pm.c
index d7a4f7aa93ef..caa34eadf8ea 100644
--- a/drivers/platform/msm/mhi/mhi_pm.c
+++ b/drivers/platform/msm/mhi/mhi_pm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -62,6 +62,7 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt,
bool force_m3)
{
int r = 0;
+ enum MHI_PM_STATE new_state;
read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock);
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
@@ -79,13 +80,20 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt,
}
if (unlikely(atomic_read(&mhi_dev_ctxt->counters.device_wake) &&
- force_m3 == false)){
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Busy, Aborting M3\n");
+ force_m3 == false)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Busy, Aborting M3\n");
read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
return -EBUSY;
}
+ if (unlikely(!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state))) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Error, no register access, PM_STATE:0x%x\n",
+ mhi_dev_ctxt->mhi_pm_state);
+ read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
+ return -EIO;
+ }
+
mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, false);
read_unlock_bh(&mhi_dev_ctxt->pm_xfer_lock);
r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event,
@@ -93,7 +101,7 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt,
mhi_dev_ctxt->mhi_state == MHI_STATE_M1,
msecs_to_jiffies(MHI_MAX_RESUME_TIMEOUT));
if (!r) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
"Failed to get M0||M1 event, timeout, current state:%s\n",
TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
return -EIO;
@@ -102,7 +110,14 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt,
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Allowing M3 State\n");
write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt);
- mhi_dev_ctxt->mhi_pm_state = MHI_PM_M3_ENTER;
+ new_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_M3_ENTER);
+ if (unlikely(new_state != MHI_PM_M3_ENTER)) {
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Error setting PM_STATE from 0x%x to 0x%x\n",
+ new_state, MHI_PM_M3_ENTER);
+ return -EIO;
+ }
mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M3);
write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Waiting for M3 completion.\n");
@@ -110,7 +125,7 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt,
mhi_dev_ctxt->mhi_state == MHI_STATE_M3,
msecs_to_jiffies(MHI_MAX_SUSPEND_TIMEOUT));
if (!r) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
"Failed to get M3 event, timeout, current state:%s\n",
TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
return -EIO;
@@ -122,6 +137,7 @@ static int mhi_pm_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt,
static int mhi_pm_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt)
{
int r;
+ enum MHI_PM_STATE cur_state;
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Entered with State:0x%x %s\n",
@@ -129,11 +145,16 @@ static int mhi_pm_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt)
TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
- mhi_dev_ctxt->mhi_pm_state = MHI_PM_M3_EXIT;
- write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_M3_EXIT);
+ if (unlikely(cur_state != MHI_PM_M3_EXIT)) {
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Error setting PM_STATE from 0x%x to 0x%x\n",
+ cur_state, MHI_PM_M3_EXIT);
+ return -EAGAIN;
+ }
/* Set and wait for M0 Event */
- write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M0);
write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
r = wait_event_timeout(*mhi_dev_ctxt->mhi_ev_wq.m0_event,
@@ -164,7 +185,7 @@ int mhi_runtime_suspend(struct device *dev)
mutex_unlock(&mhi_dev_ctxt->pm_lock);
return r;
}
- r = mhi_turn_off_pcie_link(mhi_dev_ctxt);
+ r = mhi_turn_off_pcie_link(mhi_dev_ctxt, true);
if (r) {
mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
"Failed to Turn off link ret:%d\n", r);
@@ -294,6 +315,21 @@ unlock_pm_lock:
return ret_val;
}
+static void mhi_pm_slave_mode_power_off(struct mhi_device_ctxt *mhi_dev_ctxt)
+{
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Entered with pm_state:0x%x MHI_STATE:%s\n",
+ mhi_dev_ctxt->mhi_pm_state,
+ TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
+
+ if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_DISABLE) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "MHI already in disabled state\n");
+ return;
+ }
+ process_disable_transition(MHI_PM_SHUTDOWN_PROCESS, mhi_dev_ctxt);
+}
+
static int mhi_pm_slave_mode_suspend(struct mhi_device_ctxt *mhi_dev_ctxt)
{
int r;
@@ -367,7 +403,7 @@ ssize_t sysfs_init_m3(struct device *dev, struct device_attribute *attr,
return count;
}
-int mhi_turn_off_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt)
+int mhi_turn_off_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt, bool graceful)
{
struct pci_dev *pcie_dev;
int r = 0;
@@ -376,22 +412,23 @@ int mhi_turn_off_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt)
pcie_dev = mhi_dev_ctxt->pcie_device;
if (0 == mhi_dev_ctxt->flags.link_up) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Link already marked as down, nothing to do\n");
goto exit;
}
- r = pci_save_state(pcie_dev);
- if (r) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
- "Failed to save pcie state ret: %d\n", r);
- }
- mhi_dev_ctxt->core.pcie_state = pci_store_saved_state(pcie_dev);
- pci_disable_device(pcie_dev);
- r = pci_set_power_state(pcie_dev, PCI_D3hot);
- if (r) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Failed to set pcie power state to D3hot ret:%d\n", r);
+ if (graceful) {
+ r = pci_save_state(pcie_dev);
+ if (r)
+ mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
+ "Failed to save pcie state ret: %d\n", r);
+ mhi_dev_ctxt->core.pcie_state = pci_store_saved_state(pcie_dev);
+ pci_disable_device(pcie_dev);
+ r = pci_set_power_state(pcie_dev, PCI_D3hot);
+ if (r)
+ mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
+ "Failed to set pcie power state to D3hot ret:%d\n",
+ r);
}
r = msm_pcie_pm_control(MSM_PCIE_SUSPEND,
@@ -430,21 +467,26 @@ int mhi_turn_on_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt)
mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
"Could not set bus frequency ret: %d\n", r);
- r = msm_pcie_pm_control(MSM_PCIE_RESUME,
- pcie_dev->bus->number,
- pcie_dev,
- NULL,
- 0);
+ r = msm_pcie_pm_control(MSM_PCIE_RESUME, pcie_dev->bus->number,
+ pcie_dev, NULL, 0);
if (r) {
mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
"Failed to resume pcie bus ret %d\n", r);
goto exit;
}
+ r = pci_set_power_state(pcie_dev, PCI_D0);
+ if (r) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Failed to set PCI_D0 state ret:%d\n", r);
+ goto exit;
+ }
r = pci_enable_device(pcie_dev);
- if (r)
- mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
+ if (r) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Failed to enable device ret:%d\n", r);
+ goto exit;
+ }
pci_load_and_free_saved_state(pcie_dev,
&mhi_dev_ctxt->core.pcie_state);
@@ -457,6 +499,44 @@ exit:
return r;
}
+void mhi_link_state_cb(struct msm_pcie_notify *notify)
+{
+ struct mhi_device_ctxt *mhi_dev_ctxt = NULL;
+
+ if (!notify || !notify->data) {
+ pr_err("%s: incomplete handle received\n", __func__);
+ return;
+ }
+
+ mhi_dev_ctxt = notify->data;
+ switch (notify->event) {
+ case MSM_PCIE_EVENT_LINKDOWN:
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Received MSM_PCIE_EVENT_LINKDOWN\n");
+ break;
+ case MSM_PCIE_EVENT_LINKUP:
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Received MSM_PCIE_EVENT_LINKUP\n");
+ mhi_dev_ctxt->counters.link_up_cntr++;
+ break;
+ case MSM_PCIE_EVENT_WAKEUP:
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Received MSM_PCIE_EVENT_WAKE\n");
+ __pm_stay_awake(&mhi_dev_ctxt->w_lock);
+ __pm_relax(&mhi_dev_ctxt->w_lock);
+
+ if (mhi_dev_ctxt->flags.mhi_initialized) {
+ mhi_dev_ctxt->runtime_get(mhi_dev_ctxt);
+ mhi_dev_ctxt->runtime_put(mhi_dev_ctxt);
+ }
+ break;
+ default:
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Received bad link event\n");
+ return;
+ }
+}
+
int mhi_pm_control_device(struct mhi_device *mhi_device,
enum mhi_dev_ctrl ctrl)
{
@@ -477,9 +557,34 @@ int mhi_pm_control_device(struct mhi_device *mhi_device,
return mhi_pm_slave_mode_suspend(mhi_dev_ctxt);
case MHI_DEV_CTRL_RESUME:
return mhi_pm_slave_mode_resume(mhi_dev_ctxt);
- default:
+ case MHI_DEV_CTRL_POWER_OFF:
+ mhi_pm_slave_mode_power_off(mhi_dev_ctxt);
+ break;
+ case MHI_DEV_CTRL_RDDM:
+ return bhi_rddm(mhi_dev_ctxt, false);
+ case MHI_DEV_CTRL_DE_INIT:
+ if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_DISABLE)
+ process_disable_transition(MHI_PM_SHUTDOWN_PROCESS,
+ mhi_dev_ctxt);
+ bhi_exit(mhi_dev_ctxt);
+ break;
+ case MHI_DEV_CTRL_NOTIFY_LINK_ERROR:
+ {
+ enum MHI_PM_STATE cur_state;
+
+ write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ cur_state = mhi_tryset_pm_state(mhi_dev_ctxt,
+ MHI_PM_LD_ERR_FATAL_DETECT);
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ if (unlikely(cur_state != MHI_PM_LD_ERR_FATAL_DETECT))
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Failed to transition to state 0x%x from 0x%x\n",
+ MHI_PM_LD_ERR_FATAL_DETECT, cur_state);
break;
}
- return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+ return 0;
}
EXPORT_SYMBOL(mhi_pm_control_device);
diff --git a/drivers/platform/msm/mhi/mhi_ssr.c b/drivers/platform/msm/mhi/mhi_ssr.c
index 22481dede21a..9f18b1e7ef85 100644
--- a/drivers/platform/msm/mhi/mhi_ssr.c
+++ b/drivers/platform/msm/mhi/mhi_ssr.c
@@ -13,12 +13,8 @@
#include <linux/pm_runtime.h>
#include <mhi_sys.h>
#include <mhi.h>
-#include <mhi_bhi.h>
-#include <mhi_hwio.h>
-
#include <soc/qcom/subsystem_restart.h>
#include <soc/qcom/subsystem_notif.h>
-
#include <linux/esoc_client.h>
static int mhi_ssr_notify_cb(struct notifier_block *nb,
@@ -26,35 +22,45 @@ static int mhi_ssr_notify_cb(struct notifier_block *nb,
{
struct mhi_device_ctxt *mhi_dev_ctxt =
container_of(nb, struct mhi_device_ctxt, mhi_ssr_nb);
+ enum MHI_PM_STATE cur_state;
+ struct notif_data *notif_data = (struct notif_data *)data;
+ bool crashed = notif_data->crashed;
+
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Received ESOC notifcation:%lu crashed:%d\n", action, crashed);
switch (action) {
- case SUBSYS_BEFORE_POWERUP:
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Received Subsystem event BEFORE_POWERUP\n");
- break;
- case SUBSYS_AFTER_POWERUP:
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Received Subsystem event AFTER_POWERUP\n");
- break;
- case SUBSYS_POWERUP_FAILURE:
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Received Subsystem event POWERUP_FAILURE\n");
- break;
case SUBSYS_BEFORE_SHUTDOWN:
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Received Subsystem event BEFORE_SHUTDOWN\n");
+ /*
+ * update internal states only, we'll clean up MHI context
+ * after device shutdown completely.
+ */
+ write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ cur_state = mhi_tryset_pm_state(mhi_dev_ctxt,
+ MHI_PM_LD_ERR_FATAL_DETECT);
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ if (unlikely(cur_state != MHI_PM_LD_ERR_FATAL_DETECT))
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Failed to transition to state 0x%x from 0x%x\n",
+ MHI_PM_LD_ERR_FATAL_DETECT, cur_state);
break;
case SUBSYS_AFTER_SHUTDOWN:
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Received Subsystem event AFTER_SHUTDOWN\n");
- break;
- case SUBSYS_RAMDUMP_NOTIFICATION:
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Received Subsystem event RAMDUMP\n");
+ if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_DISABLE)
+ process_disable_transition(MHI_PM_SHUTDOWN_PROCESS,
+ mhi_dev_ctxt);
+ mutex_lock(&mhi_dev_ctxt->pm_lock);
+ write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ cur_state = mhi_tryset_pm_state(mhi_dev_ctxt,
+ MHI_PM_SSR_PENDING);
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ mutex_unlock(&mhi_dev_ctxt->pm_lock);
+ if (unlikely(cur_state != MHI_PM_SSR_PENDING))
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Failed to transition to state 0x%x from 0x%x\n",
+ MHI_PM_SSR_PENDING, cur_state);
break;
default:
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Received ESOC notifcation %d, NOT handling\n",
- (int)action);
+ "Not handling esoc notification:%lu\n", action);
break;
}
return NOTIFY_OK;
@@ -91,128 +97,242 @@ int mhi_esoc_register(struct mhi_device_ctxt *mhi_dev_ctxt)
return ret_val;
}
-void mhi_notify_client(struct mhi_client_handle *client_handle,
- enum MHI_CB_REASON reason)
+/* handles sys_err, and shutdown transition */
+void process_disable_transition(enum MHI_PM_STATE transition_state,
+ struct mhi_device_ctxt *mhi_dev_ctxt)
{
- struct mhi_cb_info cb_info = {0};
- struct mhi_result result = {0};
- struct mhi_client_config *client_config;
+ enum MHI_PM_STATE cur_state, prev_state;
+ struct mhi_client_handle *client_handle;
+ struct mhi_ring *ch_ring, *bb_ring, *cmd_ring;
+ struct mhi_cmd_ctxt *cmd_ctxt;
+ struct mhi_chan_cfg *chan_cfg;
+ rwlock_t *pm_xfer_lock = &mhi_dev_ctxt->pm_xfer_lock;
+ enum MHI_CB_REASON reason;
+ u32 timeout = mhi_dev_ctxt->poll_reset_timeout_ms;
+ int i;
+ int ret;
+
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Enter with pm_state:0x%x MHI_STATE:%s transition_state:0x%x\n",
+ mhi_dev_ctxt->mhi_pm_state,
+ TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state),
+ transition_state);
- cb_info.result = NULL;
- cb_info.cb_reason = reason;
+ mutex_lock(&mhi_dev_ctxt->pm_lock);
+ write_lock_irq(pm_xfer_lock);
+ prev_state = mhi_dev_ctxt->mhi_pm_state;
+ cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, transition_state);
+ if (cur_state == transition_state) {
+ mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_DISABLE_TRANSITION;
+ mhi_dev_ctxt->flags.mhi_initialized = false;
+ }
+ write_unlock_irq(pm_xfer_lock);
- if (client_handle == NULL)
+ /* Not handling sys_err, could be middle of shut down */
+ if (unlikely(cur_state != transition_state)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Failed to transition to state 0x%x from 0x%x\n",
+ transition_state, cur_state);
+ mutex_unlock(&mhi_dev_ctxt->pm_lock);
return;
+ }
- client_config = client_handle->client_config;
-
- if (client_config->client_info.mhi_client_cb) {
- result.user_data = client_config->user_data;
- cb_info.chan = client_config->chan_info.chan_nr;
- cb_info.result = &result;
- mhi_log(client_config->mhi_dev_ctxt, MHI_MSG_INFO,
- "Calling back for chan %d, reason %d\n",
- cb_info.chan,
- reason);
- client_config->client_info.mhi_client_cb(&cb_info);
+ /*
+ * If we're shutting down trigger device into MHI reset
+ * so we can gurantee device will not access host DDR
+ * during reset
+ */
+ if (cur_state == MHI_PM_SHUTDOWN_PROCESS &&
+ MHI_REG_ACCESS_VALID(prev_state)) {
+ read_lock_bh(pm_xfer_lock);
+ mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_RESET);
+ read_unlock_bh(pm_xfer_lock);
+ mhi_test_for_device_reset(mhi_dev_ctxt);
}
-}
-void mhi_notify_clients(struct mhi_device_ctxt *mhi_dev_ctxt,
- enum MHI_CB_REASON reason)
-{
- int i;
- struct mhi_client_handle *client_handle = NULL;
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Waiting for all pending event ring processing to complete\n");
+ for (i = 0; i < mhi_dev_ctxt->mmio_info.nr_event_rings; i++) {
+ tasklet_kill(&mhi_dev_ctxt->mhi_local_event_ctxt[i].ev_task);
+ flush_work(&mhi_dev_ctxt->mhi_local_event_ctxt[i].ev_worker);
+ }
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Notifying all clients and resetting channels\n");
- for (i = 0; i < MHI_MAX_CHANNELS; ++i) {
- if (VALID_CHAN_NR(i)) {
- client_handle = mhi_dev_ctxt->client_handle_list[i];
+ if (cur_state == MHI_PM_SHUTDOWN_PROCESS)
+ reason = MHI_CB_MHI_SHUTDOWN;
+ else
+ reason = MHI_CB_SYS_ERROR;
+ ch_ring = mhi_dev_ctxt->mhi_local_chan_ctxt;
+ chan_cfg = mhi_dev_ctxt->mhi_chan_cfg;
+ bb_ring = mhi_dev_ctxt->chan_bb_list;
+ for (i = 0; i < MHI_MAX_CHANNELS;
+ i++, ch_ring++, chan_cfg++, bb_ring++) {
+ enum MHI_CHAN_STATE ch_state;
+
+ client_handle = mhi_dev_ctxt->client_handle_list[i];
+ if (client_handle)
mhi_notify_client(client_handle, reason);
+
+ mutex_lock(&chan_cfg->chan_lock);
+ spin_lock_irq(&ch_ring->ring_lock);
+ ch_state = ch_ring->ch_state;
+ ch_ring->ch_state = MHI_CHAN_STATE_DISABLED;
+ spin_unlock_irq(&ch_ring->ring_lock);
+
+ /* Reset channel and free ring */
+ if (ch_state == MHI_CHAN_STATE_ENABLED) {
+ mhi_reset_chan(mhi_dev_ctxt, i);
+ free_tre_ring(mhi_dev_ctxt, i);
+ bb_ring->rp = bb_ring->base;
+ bb_ring->wp = bb_ring->base;
+ bb_ring->ack_rp = bb_ring->base;
}
+ mutex_unlock(&chan_cfg->chan_lock);
}
-}
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Finished notifying clients\n");
-int set_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt)
-{
- u32 pcie_word_val = 0;
- int r = 0;
+ /* Release lock and wait for all pending threads to complete */
+ mutex_unlock(&mhi_dev_ctxt->pm_lock);
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Waiting for all pending threads to complete\n");
+ complete(&mhi_dev_ctxt->cmd_complete);
+ flush_work(&mhi_dev_ctxt->process_m1_worker);
+ flush_work(&mhi_dev_ctxt->st_thread_worker);
+ if (mhi_dev_ctxt->bhi_ctxt.manage_boot)
+ flush_work(&mhi_dev_ctxt->bhi_ctxt.fw_load_work);
+ if (cur_state == MHI_PM_SHUTDOWN_PROCESS)
+ flush_work(&mhi_dev_ctxt->process_sys_err_worker);
- mhi_dev_ctxt->bhi_ctxt.bhi_base = mhi_dev_ctxt->core.bar0_base;
- pcie_word_val = mhi_reg_read(mhi_dev_ctxt->bhi_ctxt.bhi_base, BHIOFF);
+ mutex_lock(&mhi_dev_ctxt->pm_lock);
- /* confirm it's a valid reading */
- if (unlikely(pcie_word_val == U32_MAX)) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
- "Invalid BHI Offset:0x%x\n", pcie_word_val);
- return -EIO;
- }
- mhi_dev_ctxt->bhi_ctxt.bhi_base += pcie_word_val;
- pcie_word_val = mhi_reg_read(mhi_dev_ctxt->bhi_ctxt.bhi_base,
- BHI_EXECENV);
- mhi_dev_ctxt->dev_exec_env = pcie_word_val;
- if (pcie_word_val == MHI_EXEC_ENV_AMSS) {
- mhi_dev_ctxt->base_state = STATE_TRANSITION_RESET;
- } else if (pcie_word_val == MHI_EXEC_ENV_PBL) {
- mhi_dev_ctxt->base_state = STATE_TRANSITION_BHI;
- } else {
- mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
- "Invalid EXEC_ENV: 0x%x\n",
- pcie_word_val);
- r = -EIO;
+ /*
+ * Shutdown has higher priority than sys_err and can be called
+ * middle of sys error, check current state to confirm state
+ * was not changed.
+ */
+ if (mhi_dev_ctxt->mhi_pm_state != cur_state) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "PM State transitioned to 0x%x while processing 0x%x\n",
+ mhi_dev_ctxt->mhi_pm_state, transition_state);
+ mutex_unlock(&mhi_dev_ctxt->pm_lock);
+ return;
}
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "EXEC_ENV: %d Base state %d\n",
- pcie_word_val, mhi_dev_ctxt->base_state);
- return r;
-}
-void mhi_link_state_cb(struct msm_pcie_notify *notify)
-{
- struct mhi_device_ctxt *mhi_dev_ctxt = NULL;
+ /* Check all counts to make sure 0 */
+ WARN_ON(atomic_read(&mhi_dev_ctxt->counters.device_wake));
+ WARN_ON(atomic_read(&mhi_dev_ctxt->counters.outbound_acks));
+ if (mhi_dev_ctxt->core.pci_master)
+ WARN_ON(atomic_read(&mhi_dev_ctxt->pcie_device->dev.
+ power.usage_count));
- if (!notify || !notify->data) {
- pr_err("%s: incomplete handle received\n", __func__);
- return;
+ /* Reset Event rings and CMD rings */
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Resetting ev ctxt and cmd ctxt\n");
+
+ cmd_ring = mhi_dev_ctxt->mhi_local_cmd_ctxt;
+ cmd_ctxt = mhi_dev_ctxt->dev_space.ring_ctxt.cmd_ctxt;
+ for (i = 0; i < NR_OF_CMD_RINGS; i++, cmd_ring++) {
+ cmd_ring->rp = cmd_ring->base;
+ cmd_ring->wp = cmd_ring->base;
+ cmd_ctxt->mhi_cmd_ring_read_ptr =
+ cmd_ctxt->mhi_cmd_ring_base_addr;
+ cmd_ctxt->mhi_cmd_ring_write_ptr =
+ cmd_ctxt->mhi_cmd_ring_base_addr;
}
+ for (i = 0; i < mhi_dev_ctxt->mmio_info.nr_event_rings; i++)
+ mhi_reset_ev_ctxt(mhi_dev_ctxt, i);
- mhi_dev_ctxt = notify->data;
- switch (notify->event) {
- case MSM_PCIE_EVENT_LINKDOWN:
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Received MSM_PCIE_EVENT_LINKDOWN\n");
- break;
- case MSM_PCIE_EVENT_LINKUP:
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Received MSM_PCIE_EVENT_LINKUP\n");
- mhi_dev_ctxt->counters.link_up_cntr++;
- break;
- case MSM_PCIE_EVENT_WAKEUP:
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Received MSM_PCIE_EVENT_WAKE\n");
- __pm_stay_awake(&mhi_dev_ctxt->w_lock);
- __pm_relax(&mhi_dev_ctxt->w_lock);
+ /*
+ * If we're the bus master disable runtime suspend
+ * we will enable it back again during AMSS transition
+ */
+ if (mhi_dev_ctxt->core.pci_master)
+ pm_runtime_forbid(&mhi_dev_ctxt->pcie_device->dev);
+
+ if (cur_state == MHI_PM_SYS_ERR_PROCESS) {
+ bool trigger_reset = false;
- if (mhi_dev_ctxt->flags.mhi_initialized) {
- mhi_dev_ctxt->runtime_get(mhi_dev_ctxt);
- mhi_dev_ctxt->runtime_put(mhi_dev_ctxt);
- }
- break;
- default:
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Received bad link event\n");
- return;
+ "Triggering device reset\n");
+ reinit_completion(&mhi_dev_ctxt->cmd_complete);
+ write_lock_irq(pm_xfer_lock);
+ /* Link can go down while processing SYS_ERR */
+ if (MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) {
+ mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_RESET);
+ mhi_init_state_transition(mhi_dev_ctxt,
+ STATE_TRANSITION_RESET);
+ trigger_reset = true;
}
+ write_unlock_irq(pm_xfer_lock);
+
+ if (trigger_reset) {
+ /*
+ * Keep the MHI state in Active (M0) state until host
+ * enter AMSS/RDDM state. Otherwise modem would error
+ * fatal if host try to enter M1 before reaching
+ * AMSS\RDDM state.
+ */
+ read_lock_bh(pm_xfer_lock);
+ mhi_assert_device_wake(mhi_dev_ctxt, false);
+ read_unlock_bh(pm_xfer_lock);
+
+ /* Wait till we enter AMSS/RDDM Exec env.*/
+ ret = wait_for_completion_timeout
+ (&mhi_dev_ctxt->cmd_complete,
+ msecs_to_jiffies(timeout));
+ if (!ret || (mhi_dev_ctxt->dev_exec_env !=
+ MHI_EXEC_ENV_AMSS &&
+ mhi_dev_ctxt->dev_exec_env !=
+ MHI_EXEC_ENV_RDDM)) {
+
+ /*
+ * device did not reset properly, notify bus
+ * master
+ */
+ if (!mhi_dev_ctxt->core.pci_master) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Notifying bus master Sys Error Status\n");
+ mhi_dev_ctxt->status_cb(
+ MHI_CB_SYS_ERROR,
+ mhi_dev_ctxt->priv_data);
+ }
+ mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt);
+ }
+ }
+ } else {
+ write_lock_irq(pm_xfer_lock);
+ cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_DISABLE);
+ write_unlock_irq(pm_xfer_lock);
+ if (unlikely(cur_state != MHI_PM_DISABLE))
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Error transition from state:0x%x to 0x%x\n",
+ cur_state, MHI_PM_DISABLE);
+
+ if (mhi_dev_ctxt->core.pci_master &&
+ cur_state == MHI_PM_DISABLE)
+ mhi_turn_off_pcie_link(mhi_dev_ctxt,
+ MHI_REG_ACCESS_VALID(prev_state));
+ }
+
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Exit with pm_state:0x%x exec_env:0x%x mhi_state:%s\n",
+ mhi_dev_ctxt->mhi_pm_state, mhi_dev_ctxt->dev_exec_env,
+ TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
+
+ mutex_unlock(&mhi_dev_ctxt->pm_lock);
}
-int init_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt)
+void mhi_sys_err_worker(struct work_struct *work)
{
- int r = 0;
+ struct mhi_device_ctxt *mhi_dev_ctxt =
+ container_of(work, struct mhi_device_ctxt,
+ process_sys_err_worker);
- r = mhi_init_state_transition(mhi_dev_ctxt, mhi_dev_ctxt->base_state);
- if (r) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
- "Failed to start state change event, to %d\n",
- mhi_dev_ctxt->base_state);
- }
- return r;
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Enter with pm_state:0x%x MHI_STATE:%s\n",
+ mhi_dev_ctxt->mhi_pm_state,
+ TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
+
+ process_disable_transition(MHI_PM_SYS_ERR_PROCESS, mhi_dev_ctxt);
}
diff --git a/drivers/platform/msm/mhi/mhi_states.c b/drivers/platform/msm/mhi/mhi_states.c
index a4da6c21b50d..c0c23c4e0756 100644
--- a/drivers/platform/msm/mhi/mhi_states.c
+++ b/drivers/platform/msm/mhi/mhi_states.c
@@ -13,6 +13,7 @@
#include "mhi_sys.h"
#include "mhi_hwio.h"
#include "mhi_trace.h"
+#include "mhi_bhi.h"
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -33,6 +34,7 @@ const char *state_transition_str(enum STATE_TRANSITION state)
[STATE_TRANSITION_LINK_DOWN] = "LINK_DOWN",
[STATE_TRANSITION_WAKE] = "WAKE",
[STATE_TRANSITION_BHIE] = "BHIE",
+ [STATE_TRANSITION_RDDM] = "RDDM",
[STATE_TRANSITION_SYS_ERR] = "SYS_ERR",
};
@@ -40,6 +42,53 @@ const char *state_transition_str(enum STATE_TRANSITION state)
mhi_states_transition_str[state] : "Invalid";
}
+int set_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt)
+{
+ u32 pcie_word_val = 0;
+ int r = 0;
+
+ mhi_dev_ctxt->bhi_ctxt.bhi_base = mhi_dev_ctxt->core.bar0_base;
+ pcie_word_val = mhi_reg_read(mhi_dev_ctxt->bhi_ctxt.bhi_base, BHIOFF);
+
+ /* confirm it's a valid reading */
+ if (unlikely(pcie_word_val == U32_MAX)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Invalid BHI Offset:0x%x\n", pcie_word_val);
+ return -EIO;
+ }
+ mhi_dev_ctxt->bhi_ctxt.bhi_base += pcie_word_val;
+ pcie_word_val = mhi_reg_read(mhi_dev_ctxt->bhi_ctxt.bhi_base,
+ BHI_EXECENV);
+ mhi_dev_ctxt->dev_exec_env = pcie_word_val;
+ if (pcie_word_val == MHI_EXEC_ENV_AMSS) {
+ mhi_dev_ctxt->base_state = STATE_TRANSITION_RESET;
+ } else if (pcie_word_val == MHI_EXEC_ENV_PBL) {
+ mhi_dev_ctxt->base_state = STATE_TRANSITION_BHI;
+ } else {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Invalid EXEC_ENV: 0x%x\n",
+ pcie_word_val);
+ r = -EIO;
+ }
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "EXEC_ENV: %d Base state %d\n",
+ pcie_word_val, mhi_dev_ctxt->base_state);
+ return r;
+}
+
+int init_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt)
+{
+ int r = 0;
+
+ r = mhi_init_state_transition(mhi_dev_ctxt, mhi_dev_ctxt->base_state);
+ if (r) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
+ "Failed to start state change event, to %d\n",
+ mhi_dev_ctxt->base_state);
+ }
+ return r;
+}
+
enum MHI_STATE mhi_get_m_state(struct mhi_device_ctxt *mhi_dev_ctxt)
{
u32 state = mhi_reg_read_field(mhi_dev_ctxt->mmio_info.mmio_addr,
@@ -47,7 +96,16 @@ enum MHI_STATE mhi_get_m_state(struct mhi_device_ctxt *mhi_dev_ctxt)
MHISTATUS_MHISTATE_MASK,
MHISTATUS_MHISTATE_SHIFT);
- return (state >= MHI_STATE_LIMIT) ? MHI_STATE_LIMIT : state;
+ return state;
+}
+
+bool mhi_in_sys_err(struct mhi_device_ctxt *mhi_dev_ctxt)
+{
+ u32 state = mhi_reg_read_field(mhi_dev_ctxt->mmio_info.mmio_addr,
+ MHISTATUS, MHISTATUS_SYSERR_MASK,
+ MHISTATUS_SYSERR_SHIFT);
+
+ return (state) ? true : false;
}
void mhi_set_m_state(struct mhi_device_ctxt *mhi_dev_ctxt,
@@ -69,6 +127,140 @@ void mhi_set_m_state(struct mhi_device_ctxt *mhi_dev_ctxt,
mhi_reg_read(mhi_dev_ctxt->mmio_info.mmio_addr, MHICTRL);
}
+/*
+ * Not all MHI states transitions are sync transitions. Linkdown, SSR, and
+ * shutdown can happen anytime asynchronously. This function will transition to
+ * new state only if it's a valid transitions.
+ *
+ * Priority increase as we go down, example while in any states from L0, start
+ * state from L1, L2, or L3 can be set. Notable exception to this rule is state
+ * DISABLE. From DISABLE state we can transition to only POR or SSR_PENDING
+ * state. Also for example while in L2 state, user cannot jump back to L1 or
+ * L0 states.
+ * Valid transitions:
+ * L0: DISABLE <--> POR
+ * DISABLE <--> SSR_PENDING
+ * POR <--> POR
+ * POR -> M0 -> M1 -> M1_M2 -> M2 --> M0
+ * M1_M2 -> M0 (Device can trigger it)
+ * M0 -> M3_ENTER -> M3 -> M3_EXIT --> M0
+ * M1 -> M3_ENTER --> M3
+ * L1: SYS_ERR_DETECT -> SYS_ERR_PROCESS --> POR
+ * L2: SHUTDOWN_PROCESS -> DISABLE -> SSR_PENDING (via SSR Notification only)
+ * L3: LD_ERR_FATAL_DETECT -> SHUTDOWN_PROCESS
+ */
+static const struct mhi_pm_transitions const mhi_state_transitions[] = {
+ /* L0 States */
+ {
+ MHI_PM_DISABLE,
+ MHI_PM_POR | MHI_PM_SSR_PENDING
+ },
+ {
+ MHI_PM_POR,
+ MHI_PM_POR | MHI_PM_DISABLE | MHI_PM_M0 |
+ MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS |
+ MHI_PM_LD_ERR_FATAL_DETECT
+ },
+ {
+ MHI_PM_M0,
+ MHI_PM_M1 | MHI_PM_M3_ENTER | MHI_PM_SYS_ERR_DETECT |
+ MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT
+ },
+ {
+ MHI_PM_M1,
+ MHI_PM_M1_M2_TRANSITION | MHI_PM_M3_ENTER |
+ MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS |
+ MHI_PM_LD_ERR_FATAL_DETECT
+ },
+ {
+ MHI_PM_M1_M2_TRANSITION,
+ MHI_PM_M2 | MHI_PM_M0 | MHI_PM_SYS_ERR_DETECT |
+ MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT
+ },
+ {
+ MHI_PM_M2,
+ MHI_PM_M0 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS |
+ MHI_PM_LD_ERR_FATAL_DETECT
+ },
+ {
+ MHI_PM_M3_ENTER,
+ MHI_PM_M3 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS |
+ MHI_PM_LD_ERR_FATAL_DETECT
+ },
+ {
+ MHI_PM_M3,
+ MHI_PM_M3_EXIT | MHI_PM_SYS_ERR_DETECT |
+ MHI_PM_SHUTDOWN_PROCESS | MHI_PM_LD_ERR_FATAL_DETECT
+ },
+ {
+ MHI_PM_M3_EXIT,
+ MHI_PM_M0 | MHI_PM_SYS_ERR_DETECT | MHI_PM_SHUTDOWN_PROCESS |
+ MHI_PM_LD_ERR_FATAL_DETECT
+ },
+ /* L1 States */
+ {
+ MHI_PM_SYS_ERR_DETECT,
+ MHI_PM_SYS_ERR_PROCESS | MHI_PM_SHUTDOWN_PROCESS |
+ MHI_PM_LD_ERR_FATAL_DETECT
+ },
+ {
+ MHI_PM_SYS_ERR_PROCESS,
+ MHI_PM_POR | MHI_PM_SHUTDOWN_PROCESS |
+ MHI_PM_LD_ERR_FATAL_DETECT
+ },
+ /* L2 States */
+ {
+ MHI_PM_SHUTDOWN_PROCESS,
+ MHI_PM_DISABLE | MHI_PM_LD_ERR_FATAL_DETECT
+ },
+ /* L3 States */
+ {
+ MHI_PM_LD_ERR_FATAL_DETECT,
+ MHI_PM_SHUTDOWN_PROCESS
+ },
+ /* From SSR notification only */
+ {
+ MHI_PM_SSR_PENDING,
+ MHI_PM_DISABLE
+ }
+};
+
+enum MHI_PM_STATE __must_check mhi_tryset_pm_state(
+ struct mhi_device_ctxt *mhi_dev_ctxt,
+ enum MHI_PM_STATE state)
+{
+ unsigned long cur_state = mhi_dev_ctxt->mhi_pm_state;
+ int index = find_last_bit(&cur_state, 32);
+
+ if (unlikely(index >= ARRAY_SIZE(mhi_state_transitions))) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "cur_state:0x%lx out side of mhi_state_transitions\n",
+ cur_state);
+ return cur_state;
+ }
+
+ if (unlikely(mhi_state_transitions[index].from_state != cur_state)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "index:%u cur_state:0x%lx != actual_state: 0x%x\n",
+ index, cur_state,
+ mhi_state_transitions[index].from_state);
+ return cur_state;
+ }
+
+ if (unlikely(!(mhi_state_transitions[index].to_states & state))) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Not allowing pm state transition from:0x%lx to:0x%x state\n",
+ cur_state, state);
+ return cur_state;
+ }
+
+ mhi_log(mhi_dev_ctxt, MHI_MSG_VERBOSE,
+ "Transition to pm state from:0x%lx to:0x%x\n",
+ cur_state, state);
+ mhi_dev_ctxt->mhi_pm_state = state;
+ return mhi_dev_ctxt->mhi_pm_state;
+}
+
static void conditional_chan_db_write(
struct mhi_device_ctxt *mhi_dev_ctxt, u32 chan)
{
@@ -158,20 +350,10 @@ static void ring_all_ev_dbs(struct mhi_device_ctxt *mhi_dev_ctxt)
}
}
-static int process_bhie_transition(struct mhi_device_ctxt *mhi_dev_ctxt,
- enum STATE_TRANSITION cur_work_item)
-{
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n");
- mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_BHIE;
- wake_up(mhi_dev_ctxt->mhi_ev_wq.bhi_event);
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n");
-
- return 0;
-}
-
int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt)
{
unsigned long flags;
+ enum MHI_PM_STATE cur_state;
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Entered With State %s\n",
@@ -190,8 +372,14 @@ int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt)
write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags);
mhi_dev_ctxt->mhi_state = MHI_STATE_M0;
- mhi_dev_ctxt->mhi_pm_state = MHI_PM_M0;
+ cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_M0);
write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags);
+ if (unlikely(cur_state != MHI_PM_M0)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Failed to transition to state 0x%x from 0x%x\n",
+ MHI_PM_M0, cur_state);
+ return -EIO;
+ }
read_lock_bh(&mhi_dev_ctxt->pm_xfer_lock);
mhi_dev_ctxt->assert_wake(mhi_dev_ctxt, true);
@@ -212,6 +400,7 @@ int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt)
void process_m1_transition(struct work_struct *work)
{
struct mhi_device_ctxt *mhi_dev_ctxt;
+ enum MHI_PM_STATE cur_state;
mhi_dev_ctxt = container_of(work,
struct mhi_device_ctxt,
@@ -224,15 +413,18 @@ void process_m1_transition(struct work_struct *work)
TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
/* We either Entered M3 or we did M3->M0 Exit */
- if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_M1) {
- write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
- mutex_unlock(&mhi_dev_ctxt->pm_lock);
- return;
- }
+ if (mhi_dev_ctxt->mhi_pm_state != MHI_PM_M1)
+ goto invalid_pm_state;
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Transitioning to M2 Transition\n");
- mhi_dev_ctxt->mhi_pm_state = MHI_PM_M1_M2_TRANSITION;
+ cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_M1_M2_TRANSITION);
+ if (unlikely(cur_state != MHI_PM_M1_M2_TRANSITION)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Failed to transition to state 0x%x from 0x%x\n",
+ MHI_PM_M1_M2_TRANSITION, cur_state);
+ goto invalid_pm_state;
+ }
mhi_dev_ctxt->counters.m1_m2++;
mhi_dev_ctxt->mhi_state = MHI_STATE_M2;
mhi_set_m_state(mhi_dev_ctxt, MHI_STATE_M2);
@@ -245,7 +437,13 @@ void process_m1_transition(struct work_struct *work)
if (mhi_dev_ctxt->mhi_pm_state == MHI_PM_M1_M2_TRANSITION) {
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Entered M2 State\n");
- mhi_dev_ctxt->mhi_pm_state = MHI_PM_M2;
+ cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_M2);
+ if (unlikely(cur_state != MHI_PM_M2)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Failed to transition to state 0x%x from 0x%x\n",
+ MHI_PM_M2, cur_state);
+ goto invalid_pm_state;
+ }
}
write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
@@ -263,11 +461,17 @@ void process_m1_transition(struct work_struct *work)
pm_request_autosuspend(&mhi_dev_ctxt->pcie_device->dev);
}
mutex_unlock(&mhi_dev_ctxt->pm_lock);
+ return;
+
+invalid_pm_state:
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ mutex_unlock(&mhi_dev_ctxt->pm_lock);
}
int process_m3_transition(struct mhi_device_ctxt *mhi_dev_ctxt)
{
unsigned long flags;
+ enum MHI_PM_STATE cur_state;
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Entered with State %s\n",
TO_MHI_STATE_STR(mhi_dev_ctxt->mhi_state));
@@ -285,25 +489,18 @@ int process_m3_transition(struct mhi_device_ctxt *mhi_dev_ctxt)
write_lock_irqsave(&mhi_dev_ctxt->pm_xfer_lock, flags);
mhi_dev_ctxt->mhi_state = MHI_STATE_M3;
- mhi_dev_ctxt->mhi_pm_state = MHI_PM_M3;
+ cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_M3);
write_unlock_irqrestore(&mhi_dev_ctxt->pm_xfer_lock, flags);
+ if (unlikely(cur_state != MHI_PM_M3)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Failed to transition to state 0x%x from 0x%x\n",
+ MHI_PM_M3, cur_state);
+ return -EIO;
+ }
wake_up(mhi_dev_ctxt->mhi_ev_wq.m3_event);
return 0;
}
-static int process_bhi_transition(
- struct mhi_device_ctxt *mhi_dev_ctxt,
- enum STATE_TRANSITION cur_work_item)
-{
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Entered\n");
- write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
- mhi_dev_ctxt->mhi_state = MHI_STATE_BHI;
- write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
- wake_up_interruptible(mhi_dev_ctxt->mhi_ev_wq.bhi_event);
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Exited\n");
- return 0;
-}
-
static int process_ready_transition(
struct mhi_device_ctxt *mhi_dev_ctxt,
enum STATE_TRANSITION cur_work_item)
@@ -313,15 +510,12 @@ static int process_ready_transition(
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Processing READY state transition\n");
- r = mhi_reset_all_thread_queues(mhi_dev_ctxt);
- if (r) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
- "Failed to reset thread queues\n");
- return r;
- }
-
write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
mhi_dev_ctxt->mhi_state = MHI_STATE_READY;
+ if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) {
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ return -EIO;
+ }
r = mhi_init_mmio(mhi_dev_ctxt);
write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
/* Initialize MMIO */
@@ -341,6 +535,10 @@ static int process_ready_transition(
}
write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ if (!MHI_REG_ACCESS_VALID(mhi_dev_ctxt->mhi_pm_state)) {
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ return -EIO;
+ }
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr, MHICTRL,
MHICTRL_MHISTATE_MASK,
@@ -350,30 +548,25 @@ static int process_ready_transition(
return r;
}
-static void mhi_reset_chan_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt,
- int chan)
-{
- struct mhi_chan_ctxt *chan_ctxt =
- &mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[chan];
- struct mhi_ring *local_chan_ctxt =
- &mhi_dev_ctxt->mhi_local_chan_ctxt[chan];
- chan_ctxt->mhi_trb_read_ptr = chan_ctxt->mhi_trb_ring_base_addr;
- chan_ctxt->mhi_trb_write_ptr = chan_ctxt->mhi_trb_ring_base_addr;
- local_chan_ctxt->rp = local_chan_ctxt->base;
- local_chan_ctxt->wp = local_chan_ctxt->base;
- local_chan_ctxt->ack_rp = local_chan_ctxt->base;
-}
-
static int process_reset_transition(
struct mhi_device_ctxt *mhi_dev_ctxt,
enum STATE_TRANSITION cur_work_item)
{
- int r = 0, i = 0;
+ int r = 0;
+ enum MHI_PM_STATE cur_state;
+
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
"Processing RESET state transition\n");
write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
mhi_dev_ctxt->mhi_state = MHI_STATE_RESET;
+ cur_state = mhi_tryset_pm_state(mhi_dev_ctxt, MHI_PM_POR);
write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ if (unlikely(cur_state != MHI_PM_POR)) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_ERROR,
+ "Error transitining from state:0x%x to:0x%x\n",
+ cur_state, MHI_PM_POR);
+ return -EIO;
+ }
mhi_dev_ctxt->counters.mhi_reset_cntr++;
r = mhi_test_for_device_reset(mhi_dev_ctxt);
@@ -387,25 +580,6 @@ static int process_reset_transition(
return r;
}
- for (i = 0; i < NR_OF_CMD_RINGS; ++i) {
- mhi_dev_ctxt->mhi_local_cmd_ctxt[i].rp =
- mhi_dev_ctxt->mhi_local_cmd_ctxt[i].base;
- mhi_dev_ctxt->mhi_local_cmd_ctxt[i].wp =
- mhi_dev_ctxt->mhi_local_cmd_ctxt[i].base;
- mhi_dev_ctxt->dev_space.ring_ctxt.cmd_ctxt[i].
- mhi_cmd_ring_read_ptr =
- mhi_v2p_addr(mhi_dev_ctxt,
- MHI_RING_TYPE_CMD_RING,
- i,
- (uintptr_t)mhi_dev_ctxt->mhi_local_cmd_ctxt[i].rp);
- }
- for (i = 0; i < mhi_dev_ctxt->mmio_info.nr_event_rings; ++i)
- mhi_reset_ev_ctxt(mhi_dev_ctxt, i);
-
- for (i = 0; i < MHI_MAX_CHANNELS; ++i) {
- if (VALID_CHAN_NR(i))
- mhi_reset_chan_ctxt(mhi_dev_ctxt, i);
- }
r = mhi_init_state_transition(mhi_dev_ctxt,
STATE_TRANSITION_READY);
if (0 != r)
@@ -441,19 +615,6 @@ static void enable_clients(struct mhi_device_ctxt *mhi_dev_ctxt,
mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Done.\n");
}
-static int process_sbl_transition(
- struct mhi_device_ctxt *mhi_dev_ctxt,
- enum STATE_TRANSITION cur_work_item)
-{
-
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO, "Enabled\n");
- write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
- mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_SBL;
- write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
- enable_clients(mhi_dev_ctxt, mhi_dev_ctxt->dev_exec_env);
- return 0;
-}
-
static int process_amss_transition(
struct mhi_device_ctxt *mhi_dev_ctxt,
enum STATE_TRANSITION cur_work_item)
@@ -465,26 +626,19 @@ static int process_amss_transition(
write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_AMSS;
write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ mhi_dev_ctxt->flags.mhi_initialized = true;
+ complete(&mhi_dev_ctxt->cmd_complete);
- if (!mhi_dev_ctxt->flags.mhi_initialized) {
- r = mhi_add_elements_to_event_rings(mhi_dev_ctxt,
+ r = mhi_add_elements_to_event_rings(mhi_dev_ctxt,
cur_work_item);
- mhi_dev_ctxt->flags.mhi_initialized = 1;
- if (r) {
- mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
- "Failed to set local chan state ret %d\n", r);
- mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt);
- return r;
- }
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "Notifying clients that MHI is enabled\n");
- enable_clients(mhi_dev_ctxt, mhi_dev_ctxt->dev_exec_env);
- } else {
- mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
- "MHI is initialized\n");
+ if (r) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
+ "Failed to set local chan state ret %d\n", r);
+ mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt);
+ return r;
}
+ enable_clients(mhi_dev_ctxt, mhi_dev_ctxt->dev_exec_env);
- complete(&mhi_dev_ctxt->cmd_complete);
/*
* runtime_allow will decrement usage_count, counts were
@@ -508,7 +662,7 @@ static int process_amss_transition(
return 0;
}
-static int process_stt_work_item(
+void process_stt_work_item(
struct mhi_device_ctxt *mhi_dev_ctxt,
enum STATE_TRANSITION cur_work_item)
{
@@ -520,7 +674,10 @@ static int process_stt_work_item(
trace_mhi_state(cur_work_item);
switch (cur_work_item) {
case STATE_TRANSITION_BHI:
- r = process_bhi_transition(mhi_dev_ctxt, cur_work_item);
+ write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ mhi_dev_ctxt->mhi_state = MHI_STATE_BHI;
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ wake_up_interruptible(mhi_dev_ctxt->mhi_ev_wq.bhi_event);
break;
case STATE_TRANSITION_RESET:
r = process_reset_transition(mhi_dev_ctxt, cur_work_item);
@@ -529,13 +686,34 @@ static int process_stt_work_item(
r = process_ready_transition(mhi_dev_ctxt, cur_work_item);
break;
case STATE_TRANSITION_SBL:
- r = process_sbl_transition(mhi_dev_ctxt, cur_work_item);
+ write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_SBL;
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ enable_clients(mhi_dev_ctxt, mhi_dev_ctxt->dev_exec_env);
break;
case STATE_TRANSITION_AMSS:
r = process_amss_transition(mhi_dev_ctxt, cur_work_item);
break;
case STATE_TRANSITION_BHIE:
- r = process_bhie_transition(mhi_dev_ctxt, cur_work_item);
+ write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_BHIE;
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ wake_up(mhi_dev_ctxt->mhi_ev_wq.bhi_event);
+ break;
+ case STATE_TRANSITION_RDDM:
+ write_lock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ mhi_dev_ctxt->dev_exec_env = MHI_EXEC_ENV_RDDM;
+ mhi_dev_ctxt->deassert_wake(mhi_dev_ctxt);
+ write_unlock_irq(&mhi_dev_ctxt->pm_xfer_lock);
+ complete(&mhi_dev_ctxt->cmd_complete);
+
+ /* Notify bus master device entered rddm mode */
+ if (!mhi_dev_ctxt->core.pci_master) {
+ mhi_log(mhi_dev_ctxt, MHI_MSG_INFO,
+ "Notifying bus master RDDM Status\n");
+ mhi_dev_ctxt->status_cb(MHI_CB_RDDM,
+ mhi_dev_ctxt->priv_data);
+ }
break;
default:
mhi_log(mhi_dev_ctxt, MHI_MSG_CRITICAL,
@@ -543,12 +721,11 @@ static int process_stt_work_item(
state_transition_str(cur_work_item));
break;
}
- return r;
}
void mhi_state_change_worker(struct work_struct *work)
{
- int r = 0;
+ int r;
struct mhi_device_ctxt *mhi_dev_ctxt = container_of(work,
struct mhi_device_ctxt,
st_thread_worker);
@@ -564,7 +741,7 @@ void mhi_state_change_worker(struct work_struct *work)
MHI_ASSERT(r == 0,
"Failed to delete element from STT workqueue\n");
spin_unlock_irq(work_q->q_lock);
- r = process_stt_work_item(mhi_dev_ctxt, cur_work_item);
+ process_stt_work_item(mhi_dev_ctxt, cur_work_item);
}
}
diff --git a/drivers/platform/msm/mhi/mhi_sys.c b/drivers/platform/msm/mhi/mhi_sys.c
index 3389de2f95b3..1d9282627d4e 100644
--- a/drivers/platform/msm/mhi/mhi_sys.c
+++ b/drivers/platform/msm/mhi/mhi_sys.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -35,15 +35,15 @@ module_param(mhi_ipc_log_lvl, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(mhi_ipc_log_lvl, "dbg lvl");
const char * const mhi_states_str[MHI_STATE_LIMIT] = {
- "RESET",
- "READY",
- "M0",
- "M1",
- "M2",
- "M3",
+ [MHI_STATE_RESET] = "RESET",
+ [MHI_STATE_READY] = "READY",
+ [MHI_STATE_M0] = "M0",
+ [MHI_STATE_M1] = "M1",
+ [MHI_STATE_M2] = "M2",
+ [MHI_STATE_M3] = "M3",
"Reserved: 0x06",
- "BHI",
- "SYS_ERR",
+ [MHI_STATE_BHI] = "BHI",
+ [MHI_STATE_SYS_ERR] = "SYS_ERR",
};
static ssize_t mhi_dbgfs_chan_read(struct file *fp, char __user *buf,
diff --git a/drivers/platform/msm/mhi_uci/mhi_uci.c b/drivers/platform/msm/mhi_uci/mhi_uci.c
index 0e28ebdd8fea..ab3c3503c2fc 100644
--- a/drivers/platform/msm/mhi_uci/mhi_uci.c
+++ b/drivers/platform/msm/mhi_uci/mhi_uci.c
@@ -33,7 +33,6 @@
#define MHI_SOFTWARE_CLIENT_LIMIT 23
#define MHI_UCI_IPC_LOG_PAGES (25)
-#define MAX_NR_TRBS_PER_CHAN 10
#define DEVICE_NAME "mhi"
#define MHI_UCI_DRIVER_NAME "mhi_uci"
#define CTRL_MAGIC 0x4C525443
@@ -95,33 +94,35 @@ struct chan_attr {
u32 nr_trbs;
enum MHI_CHAN_DIR dir;
u32 uci_ownership;
+ bool enabled;
+ struct mhi_client_handle *mhi_handle;
+ wait_queue_head_t wq;
+ struct list_head buf_head;
+ struct mutex chan_lock;
+ atomic_t avail_pkts; /* no. avail tre to read or space avail for tx */
+ u64 pkt_count;
+};
+
+struct uci_buf {
+ void *data;
+ u64 pkt_id;
+ struct list_head node;
};
struct uci_client {
- u32 out_chan;
- u32 in_chan;
- u32 out_chan_state;
- u32 in_chan_state;
struct chan_attr in_attr;
struct chan_attr out_attr;
- struct mhi_client_handle *out_handle;
- struct mhi_client_handle *in_handle;
- size_t pending_data;
- wait_queue_head_t read_wq;
- wait_queue_head_t write_wq;
- atomic_t avail_pkts;
struct device *dev;
u8 local_tiocm;
- atomic_t ref_count;
- int mhi_status;
- void *pkt_loc;
+ struct mutex client_lock; /* sync open and close */
+ int ref_count;
+ struct uci_buf *cur_buf; /* current buffer read processing */
size_t pkt_size;
- void **in_buf_list;
+ struct work_struct outbound_worker; /* clean up outbound pkts */
atomic_t out_pkt_pend_ack;
- atomic_t mhi_disabled;
+ atomic_t completion_ack;
struct mhi_uci_ctxt_t *uci_ctxt;
- struct mutex in_chan_lock;
- struct mutex out_chan_lock;
+ bool enabled;
void *uci_ipc_log;
};
@@ -133,8 +134,6 @@ struct mhi_uci_ctxt_t {
struct mutex ctrl_mutex;
struct cdev cdev[MHI_SOFTWARE_CLIENT_LIMIT];
struct uci_client *ctrl_client;
- atomic_t mhi_disabled;
- atomic_t mhi_enable_notif_wq_active;
};
struct mhi_uci_drv_ctxt {
@@ -250,6 +249,35 @@ static long mhi_uci_ctl_ioctl(struct file *file, unsigned int cmd,
static struct mhi_uci_drv_ctxt mhi_uci_drv_ctxt;
+static void mhi_uci_clean_acked_tre(struct work_struct *work)
+{
+ struct uci_client *uci_client;
+ int i = 0;
+
+ uci_client = container_of(work, struct uci_client, outbound_worker);
+ while (atomic_read(&uci_client->completion_ack)) {
+ struct uci_buf *uci_buf;
+
+ /* acquire lock per tre so we won't block other uci threads */
+ mutex_lock(&uci_client->out_attr.chan_lock);
+ uci_buf = list_first_entry_or_null(
+ &uci_client->out_attr.buf_head,
+ struct uci_buf, node);
+ if (unlikely(!uci_buf)) {
+ mutex_unlock(&uci_client->out_attr.chan_lock);
+ break;
+ }
+ list_del(&uci_buf->node);
+ kfree(uci_buf->data);
+ atomic_dec(&uci_client->completion_ack);
+ mutex_unlock(&uci_client->out_attr.chan_lock);
+ i++;
+ }
+ uci_log(uci_client->uci_ipc_log, UCI_DBG_VERBOSE,
+ "freed %d tres for chan %d\n",
+ i, uci_client->out_attr.chan_id);
+}
+
static int mhi_init_inbound(struct uci_client *client_handle)
{
int ret_val = 0;
@@ -257,37 +285,32 @@ static int mhi_init_inbound(struct uci_client *client_handle)
struct chan_attr *chan_attributes = &client_handle->in_attr;
void *data_loc = NULL;
size_t buf_size = chan_attributes->max_packet_size;
+ struct uci_buf *uci_buf;
- if (client_handle == NULL) {
- uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
- UCI_DBG_ERROR,
- "Bad Input data, quitting\n");
- return -EINVAL;
- }
chan_attributes->nr_trbs =
- mhi_get_free_desc(client_handle->in_handle);
- client_handle->in_buf_list =
- kmalloc(sizeof(void *) * chan_attributes->nr_trbs,
- GFP_KERNEL);
- if (!client_handle->in_buf_list)
- return -ENOMEM;
+ mhi_get_free_desc(client_handle->in_attr.mhi_handle);
uci_log(client_handle->uci_ipc_log,
UCI_DBG_INFO, "Channel %d supports %d desc\n",
chan_attributes->chan_id,
chan_attributes->nr_trbs);
for (i = 0; i < chan_attributes->nr_trbs; ++i) {
- data_loc = kmalloc(buf_size, GFP_KERNEL);
- uci_log(client_handle->uci_ipc_log,
- UCI_DBG_INFO,
- "Allocated buffer %p size %zd\n",
- data_loc,
- buf_size);
+ data_loc = kmalloc(buf_size + sizeof(*uci_buf), GFP_KERNEL);
+
+ /*
+ * previously allocated memory will be freed after
+ * channel close
+ */
if (data_loc == NULL)
return -ENOMEM;
- client_handle->in_buf_list[i] = data_loc;
- ret_val = mhi_queue_xfer(client_handle->in_handle,
- data_loc, buf_size, MHI_EOT);
+ uci_buf = data_loc + buf_size;
+ uci_buf->data = data_loc;
+ uci_buf->pkt_id = chan_attributes->pkt_count++;
+ uci_log(client_handle->uci_ipc_log, UCI_DBG_INFO,
+ "Allocated buffer %llu size %ld for chan:%d\n",
+ uci_buf->pkt_id, buf_size, chan_attributes->chan_id);
+ ret_val = mhi_queue_xfer(client_handle->in_attr.mhi_handle,
+ data_loc, buf_size, MHI_EOT);
if (0 != ret_val) {
kfree(data_loc);
uci_log(client_handle->uci_ipc_log,
@@ -297,139 +320,138 @@ static int mhi_init_inbound(struct uci_client *client_handle)
ret_val);
break;
}
+ list_add_tail(&uci_buf->node, &client_handle->in_attr.buf_head);
}
return ret_val;
}
static int mhi_uci_send_packet(struct mhi_client_handle **client_handle,
- void *buf, u32 size, u32 is_uspace_buf)
+ void *buf,
+ u32 size)
{
u32 nr_avail_trbs = 0;
u32 i = 0;
void *data_loc = NULL;
- uintptr_t memcpy_result = 0;
+ unsigned long memcpy_result = 0;
int data_left_to_insert = 0;
size_t data_to_insert_now = 0;
u32 data_inserted_so_far = 0;
int ret_val = 0;
- enum MHI_FLAGS flags;
struct uci_client *uci_handle;
- uci_handle = container_of(client_handle, struct uci_client,
- out_handle);
+ struct uci_buf *uci_buf;
- if (client_handle == NULL || buf == NULL ||
- !size || uci_handle == NULL)
- return -EINVAL;
-
- nr_avail_trbs = mhi_get_free_desc(*client_handle);
+ uci_handle = container_of(client_handle, struct uci_client,
+ out_attr.mhi_handle);
+ nr_avail_trbs = atomic_read(&uci_handle->out_attr.avail_pkts);
data_left_to_insert = size;
- if (0 == nr_avail_trbs)
- return 0;
-
for (i = 0; i < nr_avail_trbs; ++i) {
data_to_insert_now = min_t(size_t, data_left_to_insert,
uci_handle->out_attr.max_packet_size);
- if (is_uspace_buf) {
- data_loc = kmalloc(data_to_insert_now, GFP_KERNEL);
- if (NULL == data_loc) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
- "Failed to allocate memory 0x%zx\n",
- data_to_insert_now);
+ data_loc = kmalloc(data_to_insert_now + sizeof(*uci_buf),
+ GFP_KERNEL);
+ if (!data_loc) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
+ "Failed to allocate memory 0x%zx\n",
+ data_to_insert_now);
return -ENOMEM;
- }
- memcpy_result = copy_from_user(data_loc,
- buf + data_inserted_so_far,
- data_to_insert_now);
-
- if (0 != memcpy_result)
- goto error_memcpy;
- } else {
- data_loc = buf;
}
-
- flags = MHI_EOT;
- if (data_left_to_insert - data_to_insert_now > 0)
- flags |= MHI_CHAIN | MHI_EOB;
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
- "At trb i = %d/%d, chain = %d, eob = %d, addr 0x%p chan %d\n",
- i,
- nr_avail_trbs,
- flags & MHI_CHAIN,
- flags & MHI_EOB,
- data_loc,
- uci_handle->out_chan);
- ret_val = mhi_queue_xfer(*client_handle, data_loc,
- data_to_insert_now, flags);
-
- if (0 != ret_val) {
- goto error_queue;
+ uci_buf = data_loc + data_to_insert_now;
+ uci_buf->data = data_loc;
+ uci_buf->pkt_id = uci_handle->out_attr.pkt_count++;
+ memcpy_result = copy_from_user(uci_buf->data,
+ buf + data_inserted_so_far,
+ data_to_insert_now);
+ if (memcpy_result)
+ goto error_xfer;
+
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
+ "At trb i = %d/%d, size = %lu, id %llu chan %d\n",
+ i, nr_avail_trbs, data_to_insert_now, uci_buf->pkt_id,
+ uci_handle->out_attr.chan_id);
+ ret_val = mhi_queue_xfer(*client_handle, uci_buf->data,
+ data_to_insert_now, MHI_EOT);
+ if (ret_val) {
+ goto error_xfer;
} else {
data_left_to_insert -= data_to_insert_now;
data_inserted_so_far += data_to_insert_now;
atomic_inc(&uci_handle->out_pkt_pend_ack);
+ atomic_dec(&uci_handle->out_attr.avail_pkts);
+ list_add_tail(&uci_buf->node,
+ &uci_handle->out_attr.buf_head);
}
- if (0 == data_left_to_insert)
+ if (!data_left_to_insert)
break;
}
return data_inserted_so_far;
-error_queue:
-error_memcpy:
- kfree(data_loc);
+error_xfer:
+ kfree(uci_buf->data);
return data_inserted_so_far;
}
static int mhi_uci_send_status_cmd(struct uci_client *client)
{
+ void *buf = NULL;
struct rs232_ctrl_msg *rs232_pkt = NULL;
+ struct uci_buf *uci_buf = NULL;
struct uci_client *uci_ctrl_handle;
struct mhi_uci_ctxt_t *uci_ctxt = client->uci_ctxt;
int ret_val = 0;
- size_t pkt_size = sizeof(struct rs232_ctrl_msg);
- u32 amount_sent;
if (!uci_ctxt->ctrl_client) {
- uci_log(client->uci_ipc_log,
- UCI_DBG_INFO,
+ uci_log(client->uci_ipc_log, UCI_DBG_INFO,
"Control channel is not defined\n");
return -EIO;
}
uci_ctrl_handle = uci_ctxt->ctrl_client;
- mutex_lock(&uci_ctrl_handle->out_chan_lock);
+ mutex_lock(&uci_ctrl_handle->out_attr.chan_lock);
- if (!atomic_read(&uci_ctrl_handle->mhi_disabled) &&
- !uci_ctrl_handle->out_chan_state) {
- uci_log(uci_ctrl_handle->uci_ipc_log,
- UCI_DBG_INFO,
+ if (!uci_ctrl_handle->enabled) {
+ uci_log(uci_ctrl_handle->uci_ipc_log, UCI_DBG_INFO,
"Opening outbound control channel %d for chan:%d\n",
- uci_ctrl_handle->out_chan,
- client->out_chan);
- ret_val = mhi_open_channel(uci_ctrl_handle->out_handle);
- if (0 != ret_val) {
- uci_log(uci_ctrl_handle->uci_ipc_log,
- UCI_DBG_CRITICAL,
+ uci_ctrl_handle->out_attr.chan_id,
+ client->out_attr.chan_id);
+ if (!uci_ctrl_handle->out_attr.enabled) {
+ uci_log(uci_ctrl_handle->uci_ipc_log, UCI_DBG_CRITICAL,
+ "Channel %d is not enable\n",
+ uci_ctrl_handle->out_attr.chan_id);
+ ret_val = -EIO;
+ goto error_open;
+ }
+ ret_val = mhi_open_channel(uci_ctrl_handle->
+ out_attr.mhi_handle);
+ if (ret_val) {
+ uci_log(uci_ctrl_handle->uci_ipc_log, UCI_DBG_CRITICAL,
"Could not open chan %d, for sideband ctrl\n",
- uci_ctrl_handle->out_chan);
+ uci_ctrl_handle->out_attr.chan_id);
ret_val = -EIO;
goto error_open;
}
- uci_ctrl_handle->out_chan_state = 1;
+ uci_ctrl_handle->enabled = true;
+ }
+
+ if (mhi_get_free_desc(uci_ctrl_handle->out_attr.mhi_handle) <= 0) {
+ ret_val = -EIO;
+ goto error_open;
}
- rs232_pkt = kzalloc(sizeof(struct rs232_ctrl_msg), GFP_KERNEL);
- if (rs232_pkt == NULL) {
+ buf = kzalloc(sizeof(*rs232_pkt) + sizeof(*uci_buf), GFP_KERNEL);
+ if (!buf) {
ret_val = -ENOMEM;
goto error_open;
}
- uci_log(uci_ctrl_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
+
+
+ uci_log(uci_ctrl_handle->uci_ipc_log, UCI_DBG_VERBOSE,
"Received request to send msg for chan %d\n",
- client->out_chan);
+ client->out_attr.chan_id);
+ uci_buf = buf + sizeof(*rs232_pkt);
+ uci_buf->data = buf;
+ rs232_pkt = (struct rs232_ctrl_msg *)uci_buf->data;
rs232_pkt->preamble = CTRL_MAGIC;
if (client->local_tiocm & TIOCM_DTR)
MHI_SET_CTRL_MSG(CTRL_MSG_DTR, rs232_pkt, 1);
@@ -438,26 +460,27 @@ static int mhi_uci_send_status_cmd(struct uci_client *client)
MHI_SET_CTRL_MSG_ID(CTRL_MSG_ID, rs232_pkt, MHI_CTRL_LINE_STATE_ID);
MHI_SET_CTRL_MSG_SIZE(CTRL_MSG_SIZE, rs232_pkt, sizeof(u32));
- MHI_SET_CTRL_DEST_ID(CTRL_DEST_ID, rs232_pkt, client->out_chan);
+ MHI_SET_CTRL_DEST_ID(CTRL_DEST_ID, rs232_pkt, client->out_attr.chan_id);
- amount_sent = mhi_uci_send_packet(&uci_ctrl_handle->out_handle,
- rs232_pkt,
- pkt_size, 0);
-
- if (pkt_size != amount_sent) {
- uci_log(uci_ctrl_handle->uci_ipc_log,
- UCI_DBG_INFO,
+ ret_val = mhi_queue_xfer(uci_ctrl_handle->out_attr.mhi_handle,
+ uci_buf->data, sizeof(*rs232_pkt), MHI_EOT);
+ if (ret_val) {
+ uci_log(uci_ctrl_handle->uci_ipc_log, UCI_DBG_INFO,
"Failed to send signal for chan %d, ret : %d\n",
- client->out_chan,
- ret_val);
- goto error;
+ client->out_attr.chan_id, ret_val);
+ goto error_queue;
}
-error_open:
- mutex_unlock(&uci_ctrl_handle->out_chan_lock);
+ list_add_tail(&uci_buf->node, &uci_ctrl_handle->out_attr.buf_head);
+
+ mutex_unlock(&uci_ctrl_handle->out_attr.chan_lock);
+ return 0;
+
+ mutex_unlock(&uci_ctrl_handle->out_attr.chan_lock);
return ret_val;
-error:
- kfree(rs232_pkt);
- mutex_unlock(&uci_ctrl_handle->out_chan_lock);
+error_queue:
+ kfree(buf);
+error_open:
+ mutex_unlock(&uci_ctrl_handle->out_attr.chan_lock);
return ret_val;
}
@@ -466,6 +489,7 @@ static int mhi_uci_tiocm_set(struct uci_client *client_ctxt, u32 set, u32 clear)
u8 status_set = 0;
u8 status_clear = 0;
u8 old_status = 0;
+ int ret = 0;
mutex_lock(&client_ctxt->uci_ctxt->ctrl_mutex);
@@ -475,23 +499,21 @@ static int mhi_uci_tiocm_set(struct uci_client *client_ctxt, u32 set, u32 clear)
client_ctxt->local_tiocm |= status_set;
client_ctxt->local_tiocm &= ~status_clear;
- uci_log(client_ctxt->uci_ipc_log,
- UCI_DBG_VERBOSE,
+ uci_log(client_ctxt->uci_ipc_log, UCI_DBG_VERBOSE,
"Old TIOCM0x%x for chan %d, Current TIOCM 0x%x\n",
- old_status,
- client_ctxt->out_chan,
+ old_status, client_ctxt->out_attr.chan_id,
client_ctxt->local_tiocm);
- mutex_unlock(&client_ctxt->uci_ctxt->ctrl_mutex);
if (client_ctxt->local_tiocm != old_status) {
- uci_log(client_ctxt->uci_ipc_log,
- UCI_DBG_VERBOSE,
+ uci_log(client_ctxt->uci_ipc_log, UCI_DBG_VERBOSE,
"Setting TIOCM to 0x%x for chan %d\n",
client_ctxt->local_tiocm,
- client_ctxt->out_chan);
- return mhi_uci_send_status_cmd(client_ctxt);
+ client_ctxt->out_attr.chan_id);
+ ret = mhi_uci_send_status_cmd(client_ctxt);
}
- return 0;
+
+ mutex_unlock(&client_ctxt->uci_ctxt->ctrl_mutex);
+ return ret;
}
static long mhi_uci_ctl_ioctl(struct file *file, unsigned int cmd,
@@ -503,35 +525,26 @@ static long mhi_uci_ctl_ioctl(struct file *file, unsigned int cmd,
uci_handle = file->private_data;
if (uci_handle == NULL) {
- uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
- UCI_DBG_VERBOSE,
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_VERBOSE,
"Invalid handle for client\n");
return -ENODEV;
}
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
"Attempting to dtr cmd 0x%x arg 0x%lx for chan %d\n",
- cmd,
- arg,
- uci_handle->out_chan);
+ cmd, arg, uci_handle->out_attr.chan_id);
switch (cmd) {
case TIOCMGET:
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
- "Returning 0x%x mask\n",
- uci_handle->local_tiocm);
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
+ "Returning 0x%x mask\n", uci_handle->local_tiocm);
ret_val = uci_handle->local_tiocm;
break;
case TIOCMSET:
if (0 != copy_from_user(&set_val, (void *)arg, sizeof(set_val)))
return -ENOMEM;
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
"Attempting to set cmd 0x%x arg 0x%x for chan %d\n",
- cmd,
- set_val,
- uci_handle->out_chan);
+ cmd, set_val, uci_handle->out_attr.chan_id);
ret_val = mhi_uci_tiocm_set(uci_handle, set_val, ~set_val);
break;
default:
@@ -551,29 +564,32 @@ static unsigned int mhi_uci_client_poll(struct file *file, poll_table *wait)
return -ENODEV;
uci_ctxt = uci_handle->uci_ctxt;
- poll_wait(file, &uci_handle->read_wq, wait);
- poll_wait(file, &uci_handle->write_wq, wait);
- if (atomic_read(&uci_handle->avail_pkts) > 0) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
+ poll_wait(file, &uci_handle->in_attr.wq, wait);
+ poll_wait(file, &uci_handle->out_attr.wq, wait);
+ mutex_lock(&uci_handle->in_attr.chan_lock);
+ if (!uci_handle->in_attr.enabled || !uci_handle->enabled)
+ mask = POLLERR;
+ else if (atomic_read(&uci_handle->in_attr.avail_pkts) ||
+ uci_handle->cur_buf) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
"Client can read chan %d\n",
- uci_handle->in_chan);
+ uci_handle->in_attr.chan_id);
mask |= POLLIN | POLLRDNORM;
}
- if (!atomic_read(&uci_ctxt->mhi_disabled) &&
- (mhi_get_free_desc(uci_handle->out_handle) > 0)) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
+ mutex_unlock(&uci_handle->in_attr.chan_lock);
+ mutex_lock(&uci_handle->out_attr.chan_lock);
+ if (!uci_handle->out_attr.enabled || !uci_handle->enabled)
+ mask |= POLLERR;
+ else if (atomic_read(&uci_handle->out_attr.avail_pkts) > 0) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
"Client can write chan %d\n",
- uci_handle->out_chan);
+ uci_handle->out_attr.chan_id);
mask |= POLLOUT | POLLWRNORM;
}
-
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
+ mutex_unlock(&uci_handle->out_attr.chan_lock);
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
"Client attempted to poll chan %d, returning mask 0x%x\n",
- uci_handle->in_chan,
- mask);
+ uci_handle->in_attr.chan_id, mask);
return mask;
}
@@ -581,66 +597,67 @@ static int open_client_mhi_channels(struct uci_client *uci_client)
{
int ret_val = 0;
int r = 0;
+ struct uci_buf *itr, *tmp;
- uci_log(uci_client->uci_ipc_log,
- UCI_DBG_INFO,
+ uci_log(uci_client->uci_ipc_log, UCI_DBG_INFO,
"Starting channels %d %d\n",
- uci_client->out_chan,
- uci_client->in_chan);
- mutex_lock(&uci_client->out_chan_lock);
- mutex_lock(&uci_client->in_chan_lock);
- ret_val = mhi_open_channel(uci_client->out_handle);
+ uci_client->out_attr.chan_id,
+ uci_client->in_attr.chan_id);
+
+ ret_val = mhi_open_channel(uci_client->out_attr.mhi_handle);
if (ret_val != 0) {
if (ret_val == -ENOTCONN)
- r = -EAGAIN;
+ return -EAGAIN;
else
- r = -EIO;
- goto handle_not_rdy_err;
+ return -EIO;
}
- uci_client->out_chan_state = 1;
+ ret_val = mhi_get_free_desc(uci_client->out_attr.mhi_handle);
+ if (ret_val >= 0)
+ atomic_set(&uci_client->out_attr.avail_pkts, ret_val);
- ret_val = mhi_open_channel(uci_client->in_handle);
+ ret_val = mhi_open_channel(uci_client->in_attr.mhi_handle);
if (ret_val != 0) {
- uci_log(uci_client->uci_ipc_log,
- UCI_DBG_ERROR,
+ uci_log(uci_client->uci_ipc_log, UCI_DBG_ERROR,
"Failed to open chan %d, ret 0x%x\n",
- uci_client->out_chan,
- ret_val);
- goto handle_in_err;
+ uci_client->out_attr.chan_id, ret_val);
+ goto error_inbound_open;
}
- uci_log(uci_client->uci_ipc_log,
- UCI_DBG_INFO,
+ uci_log(uci_client->uci_ipc_log, UCI_DBG_INFO,
"Initializing inbound chan %d\n",
- uci_client->in_chan);
- uci_client->in_chan_state = 1;
+ uci_client->in_attr.chan_id);
ret_val = mhi_init_inbound(uci_client);
if (0 != ret_val) {
- uci_log(uci_client->uci_ipc_log,
- UCI_DBG_ERROR,
+ uci_log(uci_client->uci_ipc_log, UCI_DBG_ERROR,
"Failed to init inbound 0x%x, ret 0x%x\n",
- uci_client->in_chan,
- ret_val);
- }
+ uci_client->in_attr.chan_id, ret_val);
+ goto error_init_inbound;
- mutex_unlock(&uci_client->in_chan_lock);
- mutex_unlock(&uci_client->out_chan_lock);
+ }
+ atomic_set(&uci_client->completion_ack, 0);
+ uci_client->enabled = true;
return 0;
-handle_in_err:
- mhi_close_channel(uci_client->out_handle);
- uci_client->out_chan_state = 0;
-handle_not_rdy_err:
- mutex_unlock(&uci_client->in_chan_lock);
- mutex_unlock(&uci_client->out_chan_lock);
+error_init_inbound:
+ mhi_close_channel(uci_client->in_attr.mhi_handle);
+ list_for_each_entry_safe(itr, tmp, &uci_client->in_attr.buf_head,
+ node) {
+ list_del(&itr->node);
+ kfree(itr->data);
+ }
+ INIT_LIST_HEAD(&uci_client->in_attr.buf_head);
+
+error_inbound_open:
+ mhi_close_channel(uci_client->out_attr.mhi_handle);
return r;
}
static int mhi_uci_client_open(struct inode *inode,
- struct file *file_handle)
+ struct file *file_handle)
{
struct uci_client *uci_handle = NULL;
struct mhi_uci_ctxt_t *uci_ctxt = NULL, *itr;
+ const long timeout = msecs_to_jiffies(1000);
int r = 0;
int client_id = iminor(inode);
int major = imajor(inode);
@@ -654,100 +671,136 @@ static int mhi_uci_client_open(struct inode *inode,
}
}
mutex_unlock(&mhi_uci_drv_ctxt.list_lock);
+
if (!uci_ctxt || client_id >= MHI_SOFTWARE_CLIENT_LIMIT)
return -EINVAL;
uci_handle = &uci_ctxt->client_handles[client_id];
- if (atomic_read(&uci_handle->mhi_disabled)) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_INFO,
+ r = wait_event_interruptible_timeout(uci_handle->out_attr.wq,
+ uci_handle->out_attr.enabled,
+ timeout);
+ if (r < 0)
+ return -EAGAIN;
+ r = wait_event_interruptible_timeout(uci_handle->in_attr.wq,
+ uci_handle->in_attr.enabled,
+ timeout);
+ if (r < 0)
+ return -EAGAIN;
+ r = 0;
+ mutex_lock(&uci_handle->client_lock);
+ mutex_lock(&uci_handle->out_attr.chan_lock);
+ mutex_lock(&uci_handle->in_attr.chan_lock);
+ if (!uci_handle->out_attr.enabled || !uci_handle->in_attr.enabled) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
"MHI channel still disable for, client %d\n",
client_id);
- msleep(500);
+ mutex_unlock(&uci_handle->in_attr.chan_lock);
+ mutex_unlock(&uci_handle->out_attr.chan_lock);
+ mutex_unlock(&uci_handle->client_lock);
return -EAGAIN;
}
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_INFO,
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
"Client opened device node 0x%x, ref count 0x%x\n",
- client_id,
- atomic_read(&uci_handle->ref_count));
+ client_id, uci_handle->ref_count);
- if (1 == atomic_add_return(1, &uci_handle->ref_count)) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_INFO,
- "Opening channels client %d\n",
+ if (++uci_handle->ref_count == 1) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
+ "Opening channels client %d for first time\n",
client_id);
r = open_client_mhi_channels(uci_handle);
- if (r)
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_INFO,
- "Failed to open channels ret %d\n",
- r);
+ if (r) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
+ "Failed to open channels ret %d\n", r);
+ uci_handle->ref_count--;
+ }
}
+ mutex_unlock(&uci_handle->in_attr.chan_lock);
+ mutex_unlock(&uci_handle->out_attr.chan_lock);
+ mutex_unlock(&uci_handle->client_lock);
file_handle->private_data = uci_handle;
return r;
}
static int mhi_uci_client_release(struct inode *mhi_inode,
- struct file *file_handle)
+ struct file *file_handle)
{
struct uci_client *uci_handle = file_handle->private_data;
u32 nr_in_bufs = 0;
int in_chan = 0;
- int i = 0;
u32 buf_size = 0;
- if (uci_handle == NULL)
- return -EINVAL;
-
+ mutex_lock(&uci_handle->client_lock);
in_chan = uci_handle->in_attr.chan_id;
nr_in_bufs = uci_handle->in_attr.nr_trbs;
buf_size = uci_handle->in_attr.max_packet_size;
+ uci_handle->ref_count--;
+ if (!uci_handle->ref_count) {
+ struct uci_buf *itr, *tmp;
- if (atomic_sub_return(1, &uci_handle->ref_count) == 0) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_ERROR,
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_ERROR,
"Last client left, closing channel 0x%x\n",
in_chan);
+ mutex_lock(&uci_handle->in_attr.chan_lock);
+ mutex_lock(&uci_handle->out_attr.chan_lock);
+
if (atomic_read(&uci_handle->out_pkt_pend_ack))
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_CRITICAL,
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
"Still waiting on %d acks!, chan %d\n",
atomic_read(&uci_handle->out_pkt_pend_ack),
uci_handle->out_attr.chan_id);
- mhi_close_channel(uci_handle->out_handle);
- mhi_close_channel(uci_handle->in_handle);
- uci_handle->out_chan_state = 0;
- uci_handle->in_chan_state = 0;
+ atomic_set(&uci_handle->in_attr.avail_pkts, 0);
+ if (uci_handle->in_attr.enabled)
+ mhi_close_channel(uci_handle->in_attr.mhi_handle);
+ list_for_each_entry_safe(itr, tmp,
+ &uci_handle->in_attr.buf_head, node) {
+ list_del(&itr->node);
+ kfree(itr->data);
+ }
+ if (uci_handle->cur_buf)
+ kfree(uci_handle->cur_buf->data);
+ uci_handle->cur_buf = NULL;
+ INIT_LIST_HEAD(&uci_handle->in_attr.buf_head);
+ atomic_set(&uci_handle->out_attr.avail_pkts, 0);
atomic_set(&uci_handle->out_pkt_pend_ack, 0);
- for (i = 0; i < nr_in_bufs; ++i) {
- kfree((void *)uci_handle->in_buf_list[i]);
+ if (uci_handle->out_attr.enabled)
+ mhi_close_channel(uci_handle->out_attr.mhi_handle);
+ list_for_each_entry_safe(itr, tmp,
+ &uci_handle->out_attr.buf_head, node) {
+ list_del(&itr->node);
+ kfree(itr->data);
}
- kfree(uci_handle->in_buf_list);
- atomic_set(&uci_handle->avail_pkts, 0);
+ INIT_LIST_HEAD(&uci_handle->out_attr.buf_head);
+ uci_handle->enabled = false;
+ mutex_unlock(&uci_handle->out_attr.chan_lock);
+ flush_work(&uci_handle->outbound_worker);
+ atomic_set(&uci_handle->completion_ack, 0);
+ mutex_unlock(&uci_handle->in_attr.chan_lock);
} else {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_ERROR,
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
"Client close chan %d, ref count 0x%x\n",
iminor(mhi_inode),
- atomic_read(&uci_handle->ref_count));
+ uci_handle->ref_count);
}
+ mutex_unlock(&uci_handle->client_lock);
+
return 0;
}
-static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
- size_t uspace_buf_size, loff_t *bytes_pending)
+static ssize_t mhi_uci_client_read(struct file *file,
+ char __user *buf,
+ size_t uspace_buf_size,
+ loff_t *bytes_pending)
{
struct uci_client *uci_handle = NULL;
struct mhi_client_handle *client_handle = NULL;
int ret_val = 0;
size_t buf_size = 0;
- struct mutex *mutex;
+ struct mutex *chan_lock;
u32 chan = 0;
- ssize_t bytes_copied = 0;
+ size_t bytes_copied = 0;
u32 addr_offset = 0;
struct mhi_result result;
@@ -756,213 +809,194 @@ static ssize_t mhi_uci_client_read(struct file *file, char __user *buf,
return -EINVAL;
uci_handle = file->private_data;
- client_handle = uci_handle->in_handle;
- mutex = &uci_handle->in_chan_lock;
- chan = uci_handle->in_chan;
- mutex_lock(mutex);
+ client_handle = uci_handle->in_attr.mhi_handle;
+ chan_lock = &uci_handle->in_attr.chan_lock;
+ chan = uci_handle->in_attr.chan_id;
buf_size = uci_handle->in_attr.max_packet_size;
result.buf_addr = NULL;
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
- "Client attempted read on chan %d\n",
- chan);
- do {
- if (!uci_handle->pkt_loc &&
- !atomic_read(&uci_handle->uci_ctxt->mhi_disabled)) {
- ret_val = mhi_poll_inbound(client_handle, &result);
- if (ret_val) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_ERROR,
- "Failed to poll inbound ret %d avail pkt %d\n",
- ret_val,
- atomic_read(&uci_handle->avail_pkts));
- }
- if (result.buf_addr)
- uci_handle->pkt_loc = result.buf_addr;
- else
- uci_handle->pkt_loc = 0;
- uci_handle->pkt_size = result.bytes_xferd;
- *bytes_pending = uci_handle->pkt_size;
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
- "Got pkt size 0x%zx at addr 0x%lx, chan %d\n",
- uci_handle->pkt_size,
- (uintptr_t)result.buf_addr,
- chan);
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
+ "Client attempted read on chan %d\n", chan);
+
+ mutex_lock(chan_lock);
+
+ /* confirm channel is active */
+ if (!uci_handle->in_attr.enabled || !uci_handle->enabled) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
+ "chan:%d is disabled\n", chan);
+ ret_val = -ERESTARTSYS;
+ goto read_error;
+ }
+
+ /* No data available to read, wait */
+ if (!uci_handle->cur_buf &&
+ !atomic_read(&uci_handle->in_attr.avail_pkts)) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
+ "No data available to read for chan:%d waiting\n",
+ chan);
+ mutex_unlock(chan_lock);
+ ret_val = wait_event_interruptible(uci_handle->in_attr.wq,
+ (atomic_read(&uci_handle->in_attr.avail_pkts) ||
+ !uci_handle->in_attr.enabled));
+ mutex_lock(chan_lock);
+ if (ret_val == -ERESTARTSYS) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
+ "Exit signal caught for chan:%d\n", chan);
+ goto read_error;
+
}
- if ((*bytes_pending == 0 || uci_handle->pkt_loc == 0) &&
- (atomic_read(&uci_handle->avail_pkts) <= 0)) {
- /* If nothing was copied yet, wait for data */
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
- "No data avail_pkts %d, chan %d\n",
- atomic_read(&uci_handle->avail_pkts),
- chan);
- ret_val = wait_event_interruptible(
- uci_handle->read_wq,
- (atomic_read(&uci_handle->avail_pkts) > 0));
- if (ret_val == -ERESTARTSYS) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_ERROR,
- "Exit signal caught\n");
- goto error;
- }
- /* A pending reset exists */
- } else if ((atomic_read(&uci_handle->avail_pkts) > 0) &&
- 0 == uci_handle->pkt_size &&
- 0 == uci_handle->pkt_loc &&
- uci_handle->mhi_status == -ENETRESET) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_ERROR,
- "Detected pending reset, reporting chan %d\n",
- chan);
- atomic_dec(&uci_handle->avail_pkts);
- uci_handle->mhi_status = 0;
- mutex_unlock(mutex);
- return -ENETRESET;
- /* A valid packet was returned from MHI */
- } else if (atomic_read(&uci_handle->avail_pkts) &&
- uci_handle->pkt_size != 0 &&
- uci_handle->pkt_loc != 0) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
- "Got packet: avail pkts %d phy_adr 0x%p, chan %d\n",
- atomic_read(&uci_handle->avail_pkts),
- result.buf_addr,
- chan);
- break;
- /*
- * MHI did not return a valid packet, but we have one
- * which we did not finish returning to user
- */
- } else {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_CRITICAL,
- "chan %d err: avail pkts %d mhi_stat%d\n",
- chan,
- atomic_read(&uci_handle->avail_pkts),
- uci_handle->mhi_status);
- return -EIO;
+ if (!uci_handle->in_attr.enabled || !uci_handle->enabled) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
+ "chan:%d is disabled\n", chan);
+ ret_val = -ERESTARTSYS;
+ goto read_error;
}
- } while (!uci_handle->pkt_loc);
+ }
- if (uspace_buf_size >= *bytes_pending) {
- addr_offset = uci_handle->pkt_size - *bytes_pending;
- if (0 != copy_to_user(buf,
- uci_handle->pkt_loc + addr_offset,
- *bytes_pending)) {
+ /* new read, get the data from MHI */
+ if (!uci_handle->cur_buf) {
+ struct uci_buf *cur_buf;
+
+ ret_val = mhi_poll_inbound(client_handle, &result);
+ if (unlikely(ret_val || !result.buf_addr)) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_ERROR,
+ "Failed to poll inbound ret %d avail_pkt %d\n",
+ ret_val,
+ atomic_read(&uci_handle->in_attr.avail_pkts));
+ goto read_error;
+ }
+ cur_buf = list_first_entry_or_null(
+ &uci_handle->in_attr.buf_head,
+ struct uci_buf, node);
+ if (unlikely(!cur_buf)) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_ERROR,
+ "Received completion cb but no packets queued, avail_pkt:%d\n",
+ atomic_read(&uci_handle->in_attr.avail_pkts));
ret_val = -EIO;
- goto error;
+ goto read_error;
}
- bytes_copied = *bytes_pending;
- *bytes_pending = 0;
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
- "Copied 0x%zx of 0x%x, chan %d\n",
- bytes_copied,
- (u32)*bytes_pending,
- chan);
- } else {
- addr_offset = uci_handle->pkt_size - *bytes_pending;
- if (copy_to_user(buf,
- (void *)(uintptr_t)uci_handle->pkt_loc +
- addr_offset,
- uspace_buf_size) != 0) {
+ if (unlikely(cur_buf->data != result.buf_addr)) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_ERROR,
+ "Receive out of order packet id:%llu\n",
+ cur_buf->pkt_id);
ret_val = -EIO;
- goto error;
+ goto read_error;
}
- bytes_copied = uspace_buf_size;
- *bytes_pending -= uspace_buf_size;
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
- "Copied 0x%zx of 0x%x,chan %d\n",
- bytes_copied,
- (u32)*bytes_pending,
- chan);
+
+ list_del(&cur_buf->node);
+ uci_handle->cur_buf = cur_buf;
+ *bytes_pending = result.bytes_xferd;
+ uci_handle->pkt_size = result.bytes_xferd;
+ atomic_dec(&uci_handle->in_attr.avail_pkts);
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
+ "Got pkt @ %llu size:%llu for chan:%d\n",
+ uci_handle->cur_buf->pkt_id, *bytes_pending, chan);
}
+
+ /* Copy the buffer to user space */
+ bytes_copied = min_t(size_t, uspace_buf_size, *bytes_pending);
+ addr_offset = uci_handle->pkt_size - *bytes_pending;
+ ret_val = copy_to_user(buf, uci_handle->cur_buf->data + addr_offset,
+ bytes_copied);
+ if (ret_val != 0)
+ goto read_error;
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
+ "Copied %lu of %llu bytes for chan:%d\n",
+ bytes_copied, *bytes_pending, chan);
+ *bytes_pending -= bytes_copied;
+
/* We finished with this buffer, map it back */
if (*bytes_pending == 0) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
- "Pkt loc %p ,chan %d\n",
- uci_handle->pkt_loc,
- chan);
- memset(uci_handle->pkt_loc, 0, buf_size);
- atomic_dec(&uci_handle->avail_pkts);
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
- "Decremented avail pkts avail 0x%x\n",
- atomic_read(&uci_handle->avail_pkts));
- ret_val = mhi_queue_xfer(client_handle, uci_handle->pkt_loc,
+ struct uci_buf *uci_buf = uci_handle->cur_buf;
+
+ uci_handle->cur_buf = NULL;
+ uci_buf->pkt_id = uci_handle->in_attr.pkt_count++;
+ memset(uci_buf->data, 0xdeadbeef, buf_size);
+ ret_val = mhi_queue_xfer(client_handle, uci_buf->data,
buf_size, MHI_EOT);
if (0 != ret_val) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_ERROR,
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_ERROR,
"Failed to recycle element\n");
- ret_val = -EIO;
- goto error;
+ kfree(uci_buf->data);
+ goto read_error;
}
- uci_handle->pkt_loc = 0;
+ list_add_tail(&uci_buf->node, &uci_handle->in_attr.buf_head);
}
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
- "Returning 0x%zx bytes, 0x%x bytes left\n",
- bytes_copied,
- (u32)*bytes_pending);
- mutex_unlock(mutex);
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
+ "Returning %lu bytes, %llu bytes left\n",
+ bytes_copied, *bytes_pending);
+ mutex_unlock(chan_lock);
return bytes_copied;
-error:
- mutex_unlock(mutex);
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_ERROR,
- "Returning %d\n",
- ret_val);
+
+read_error:
+ mutex_unlock(chan_lock);
return ret_val;
}
static ssize_t mhi_uci_client_write(struct file *file,
- const char __user *buf,
- size_t count, loff_t *offp)
+ const char __user *buf,
+ size_t count,
+ loff_t *offp)
{
struct uci_client *uci_handle = NULL;
+ struct chan_attr *chan_attr;
+ size_t bytes_transferrd = 0;
int ret_val = 0;
u32 chan = 0xFFFFFFFF;
- if (file == NULL || buf == NULL ||
- !count || file->private_data == NULL)
+ if (file == NULL || buf == NULL || !count ||
+ file->private_data == NULL)
return -EINVAL;
else
uci_handle = file->private_data;
- chan = uci_handle->out_chan;
- mutex_lock(&uci_handle->out_chan_lock);
-
- while (ret_val == 0) {
- ret_val = mhi_uci_send_packet(&uci_handle->out_handle,
- (void *)buf, count, 1);
- if (!ret_val) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
- "No descriptors available, did we poll, chan %d?\n",
- chan);
- mutex_unlock(&uci_handle->out_chan_lock);
- ret_val =
- wait_event_interruptible(
- uci_handle->write_wq,
- mhi_get_free_desc(uci_handle->out_handle) > 0);
- mutex_lock(&uci_handle->out_chan_lock);
- if (-ERESTARTSYS == ret_val) {
- goto sys_interrupt;
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_WARNING,
- "Waitqueue cancelled by system\n");
- }
+ chan_attr = &uci_handle->out_attr;
+ chan = chan_attr->chan_id;
+ mutex_lock(&chan_attr->chan_lock);
+
+ if (!chan_attr->enabled || !uci_handle->enabled) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
+ "Link is disabled\n");
+ ret_val = -ERESTARTSYS;
+ goto sys_interrupt;
+ }
+
+ while (bytes_transferrd != count) {
+ ret_val = mhi_uci_send_packet(&chan_attr->mhi_handle,
+ (void *)buf, count);
+ if (ret_val < 0)
+ goto sys_interrupt;
+
+ bytes_transferrd += ret_val;
+ if (bytes_transferrd == count)
+ break;
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
+ "No descriptors available, did we poll, chan %d?\n",
+ chan);
+ mutex_unlock(&chan_attr->chan_lock);
+ ret_val = wait_event_interruptible(chan_attr->wq,
+ (atomic_read(&chan_attr->avail_pkts) ||
+ !chan_attr->enabled));
+ mutex_lock(&chan_attr->chan_lock);
+ if (-ERESTARTSYS == ret_val) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
+ "Waitqueue cancelled by system\n");
+ goto sys_interrupt;
+ }
+ if (!chan_attr->enabled || !uci_handle->enabled) {
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
+ "Link is disabled\n");
+ ret_val = -ERESTARTSYS;
+ goto sys_interrupt;
}
}
+
+ mutex_unlock(&chan_attr->chan_lock);
+ return bytes_transferrd;
+
sys_interrupt:
- mutex_unlock(&uci_handle->out_chan_lock);
+ mutex_unlock(&chan_attr->chan_lock);
return ret_val;
}
@@ -1022,7 +1056,12 @@ static int uci_init_client_attributes(struct mhi_uci_ctxt_t *uci_ctxt,
if (chan_attrib->chan_id == ctrl_chan)
uci_ctxt->ctrl_client = client;
+
+ INIT_LIST_HEAD(&chan_attrib->buf_head);
+ mutex_init(&chan_attrib->chan_lock);
+ atomic_set(&chan_attrib->avail_pkts, 0);
}
+ INIT_WORK(&client->outbound_worker, mhi_uci_clean_acked_tre);
}
error_dts:
@@ -1030,35 +1069,6 @@ error_dts:
return ret_val;
}
-static int process_mhi_disabled_notif_sync(struct uci_client *uci_handle)
-{
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_INFO,
- "Entered.\n");
- if (uci_handle->mhi_status != -ENETRESET) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_CRITICAL,
- "Setting reset for chan %d\n",
- uci_handle->out_chan);
- uci_handle->pkt_size = 0;
- uci_handle->pkt_loc = NULL;
- uci_handle->mhi_status = -ENETRESET;
- atomic_set(&uci_handle->avail_pkts, 1);
- mhi_close_channel(uci_handle->out_handle);
- mhi_close_channel(uci_handle->in_handle);
- uci_handle->out_chan_state = 0;
- uci_handle->in_chan_state = 0;
- wake_up(&uci_handle->read_wq);
- } else {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_CRITICAL,
- "Chan %d state already reset\n",
- uci_handle->out_chan);
- }
- uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO, "Exited\n");
- return 0;
-}
-
static void process_rs232_state(struct uci_client *ctrl_client,
struct mhi_result *result)
{
@@ -1071,15 +1081,13 @@ static void process_rs232_state(struct uci_client *ctrl_client,
mutex_lock(&uci_ctxt->ctrl_mutex);
if (result->transaction_status != 0) {
- uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
- UCI_DBG_ERROR,
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR,
"Non successful transfer code 0x%x\n",
result->transaction_status);
goto error_bad_xfer;
}
if (result->bytes_xferd != sizeof(struct rs232_ctrl_msg)) {
- uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
- UCI_DBG_ERROR,
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_ERROR,
"Buffer is of wrong size is: 0x%zx: expected 0x%zx\n",
result->bytes_xferd,
sizeof(struct rs232_ctrl_msg));
@@ -1088,8 +1096,8 @@ static void process_rs232_state(struct uci_client *ctrl_client,
rs232_pkt = result->buf_addr;
MHI_GET_CTRL_DEST_ID(CTRL_DEST_ID, rs232_pkt, chan);
for (i = 0; i < MHI_SOFTWARE_CLIENT_LIMIT; i++)
- if (chan == uci_ctxt->client_handles[i].out_chan ||
- chan == uci_ctxt->client_handles[i].in_chan) {
+ if (chan == uci_ctxt->client_handles[i].out_attr.chan_id ||
+ chan == uci_ctxt->client_handles[i].in_attr.chan_id) {
client = &uci_ctxt->client_handles[i];
break;
}
@@ -1114,13 +1122,12 @@ static void process_rs232_state(struct uci_client *ctrl_client,
error_bad_xfer:
error_size:
memset(rs232_pkt, 0, sizeof(struct rs232_ctrl_msg));
- ret_val = mhi_queue_xfer(ctrl_client->in_handle,
+ ret_val = mhi_queue_xfer(ctrl_client->in_attr.mhi_handle,
result->buf_addr,
result->bytes_xferd,
result->flags);
if (0 != ret_val) {
- uci_log(ctrl_client->uci_ipc_log,
- UCI_DBG_ERROR,
+ uci_log(ctrl_client->uci_ipc_log, UCI_DBG_ERROR,
"Failed to recycle ctrl msg buffer\n");
}
mutex_unlock(&uci_ctxt->ctrl_mutex);
@@ -1129,13 +1136,12 @@ error_size:
static void parse_inbound_ack(struct uci_client *uci_handle,
struct mhi_result *result)
{
- atomic_inc(&uci_handle->avail_pkts);
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
+ atomic_inc(&uci_handle->in_attr.avail_pkts);
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
"Received cb on chan %d, avail pkts: 0x%x\n",
- uci_handle->in_chan,
- atomic_read(&uci_handle->avail_pkts));
- wake_up(&uci_handle->read_wq);
+ uci_handle->in_attr.chan_id,
+ atomic_read(&uci_handle->in_attr.avail_pkts));
+ wake_up(&uci_handle->in_attr.wq);
if (uci_handle == uci_handle->uci_ctxt->ctrl_client)
process_rs232_state(uci_handle, result);
}
@@ -1143,25 +1149,25 @@ static void parse_inbound_ack(struct uci_client *uci_handle,
static void parse_outbound_ack(struct uci_client *uci_handle,
struct mhi_result *result)
{
- kfree(result->buf_addr);
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
"Received ack on chan %d, pending acks: 0x%x\n",
- uci_handle->out_chan,
+ uci_handle->out_attr.chan_id,
atomic_read(&uci_handle->out_pkt_pend_ack));
atomic_dec(&uci_handle->out_pkt_pend_ack);
- if (mhi_get_free_desc(uci_handle->out_handle))
- wake_up(&uci_handle->write_wq);
+ atomic_inc(&uci_handle->out_attr.avail_pkts);
+ atomic_inc(&uci_handle->completion_ack);
+ wake_up(&uci_handle->out_attr.wq);
+ schedule_work(&uci_handle->outbound_worker);
}
static void uci_xfer_cb(struct mhi_cb_info *cb_info)
{
struct uci_client *uci_handle = NULL;
struct mhi_result *result;
+ struct chan_attr *chan_attr;
if (!cb_info || !cb_info->result) {
- uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log,
- UCI_DBG_CRITICAL,
+ uci_log(mhi_uci_drv_ctxt.mhi_uci_ipc_log, UCI_DBG_CRITICAL,
"Bad CB info from MHI\n");
return;
}
@@ -1169,22 +1175,23 @@ static void uci_xfer_cb(struct mhi_cb_info *cb_info)
uci_handle = cb_info->result->user_data;
switch (cb_info->cb_reason) {
case MHI_CB_MHI_ENABLED:
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_INFO,
- "MHI enabled CB received.\n");
- atomic_set(&uci_handle->mhi_disabled, 0);
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
+ "MHI enabled CB received for chan %d\n",
+ cb_info->chan);
+ chan_attr = (cb_info->chan % 2) ? &uci_handle->in_attr :
+ &uci_handle->out_attr;
+ mutex_lock(&chan_attr->chan_lock);
+ chan_attr->enabled = true;
+ mutex_unlock(&chan_attr->chan_lock);
+ wake_up(&chan_attr->wq);
break;
case MHI_CB_MHI_DISABLED:
- atomic_set(&uci_handle->mhi_disabled, 1);
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_INFO,
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_INFO,
"MHI disabled CB received\n");
- process_mhi_disabled_notif_sync(uci_handle);
break;
case MHI_CB_XFER:
if (!cb_info->result) {
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_CRITICAL,
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_CRITICAL,
"Failed to obtain mhi result from CB\n");
return;
}
@@ -1195,8 +1202,7 @@ static void uci_xfer_cb(struct mhi_cb_info *cb_info)
parse_outbound_ack(uci_handle, result);
break;
default:
- uci_log(uci_handle->uci_ipc_log,
- UCI_DBG_VERBOSE,
+ uci_log(uci_handle->uci_ipc_log, UCI_DBG_VERBOSE,
"Cannot handle cb reason 0x%x\n",
cb_info->cb_reason);
}
@@ -1208,48 +1214,40 @@ static int mhi_register_client(struct uci_client *mhi_client,
int ret_val = 0;
struct mhi_client_info_t client_info;
- uci_log(mhi_client->uci_ipc_log,
- UCI_DBG_INFO,
+ uci_log(mhi_client->uci_ipc_log, UCI_DBG_INFO,
"Setting up workqueues\n");
- init_waitqueue_head(&mhi_client->read_wq);
- init_waitqueue_head(&mhi_client->write_wq);
- mhi_client->out_chan = mhi_client->out_attr.chan_id;
- mhi_client->in_chan = mhi_client->in_attr.chan_id;
-
- mutex_init(&mhi_client->in_chan_lock);
- mutex_init(&mhi_client->out_chan_lock);
- atomic_set(&mhi_client->mhi_disabled, 1);
+ init_waitqueue_head(&mhi_client->in_attr.wq);
+ init_waitqueue_head(&mhi_client->out_attr.wq);
- uci_log(mhi_client->uci_ipc_log,
- UCI_DBG_INFO,
+ uci_log(mhi_client->uci_ipc_log, UCI_DBG_INFO,
"Registering chan %d\n",
- mhi_client->out_chan);
+ mhi_client->out_attr.chan_id);
client_info.dev = dev;
client_info.node_name = "qcom,mhi";
client_info.user_data = mhi_client;
client_info.mhi_client_cb = uci_xfer_cb;
- client_info.chan = mhi_client->out_chan;
+ client_info.chan = mhi_client->out_attr.chan_id;
client_info.max_payload = mhi_client->out_attr.max_packet_size;
- ret_val = mhi_register_channel(&mhi_client->out_handle, &client_info);
+ ret_val = mhi_register_channel(&mhi_client->out_attr.mhi_handle,
+ &client_info);
if (0 != ret_val)
uci_log(mhi_client->uci_ipc_log,
UCI_DBG_ERROR,
"Failed to init outbound chan 0x%x, ret 0x%x\n",
- mhi_client->out_chan,
+ mhi_client->out_attr.chan_id,
ret_val);
- uci_log(mhi_client->uci_ipc_log,
- UCI_DBG_INFO,
+ uci_log(mhi_client->uci_ipc_log, UCI_DBG_INFO,
"Registering chan %d\n",
- mhi_client->in_chan);
+ mhi_client->in_attr.chan_id);
client_info.max_payload = mhi_client->in_attr.max_packet_size;
- client_info.chan = mhi_client->in_chan;
- ret_val = mhi_register_channel(&mhi_client->in_handle, &client_info);
+ client_info.chan = mhi_client->in_attr.chan_id;
+ ret_val = mhi_register_channel(&mhi_client->in_attr.mhi_handle,
+ &client_info);
if (0 != ret_val)
- uci_log(mhi_client->uci_ipc_log,
- UCI_DBG_ERROR,
+ uci_log(mhi_client->uci_ipc_log, UCI_DBG_ERROR,
"Failed to init inbound chan 0x%x, ret 0x%x\n",
- mhi_client->in_chan,
+ mhi_client->in_attr.chan_id,
ret_val);
return 0;
}
@@ -1313,6 +1311,7 @@ static int mhi_uci_probe(struct platform_device *pdev)
struct uci_client *uci_client = &uci_ctxt->client_handles[i];
uci_client->uci_ctxt = uci_ctxt;
+ mutex_init(&uci_client->client_lock);
if (uci_client->in_attr.uci_ownership) {
ret_val = mhi_register_client(uci_client,
&pdev->dev);
@@ -1328,10 +1327,10 @@ static int mhi_uci_probe(struct platform_device *pdev)
snprintf(node_name,
sizeof(node_name),
"mhi_uci_%04x_%02u.%02u.%02u_%d",
- uci_client->out_handle->dev_id,
- uci_client->out_handle->domain,
- uci_client->out_handle->bus,
- uci_client->out_handle->slot,
+ uci_client->out_attr.mhi_handle->dev_id,
+ uci_client->out_attr.mhi_handle->domain,
+ uci_client->out_attr.mhi_handle->bus,
+ uci_client->out_attr.mhi_handle->slot,
uci_client->out_attr.chan_id);
uci_client->uci_ipc_log = ipc_log_context_create
(MHI_UCI_IPC_LOG_PAGES,
@@ -1380,12 +1379,12 @@ static int mhi_uci_probe(struct platform_device *pdev)
uci_ctxt->dev_t + i,
NULL,
DEVICE_NAME "_%04x_%02u.%02u.%02u%s%d",
- uci_client->out_handle->dev_id,
- uci_client->out_handle->domain,
- uci_client->out_handle->bus,
- uci_client->out_handle->slot,
+ uci_client->out_attr.mhi_handle->dev_id,
+ uci_client->out_attr.mhi_handle->domain,
+ uci_client->out_attr.mhi_handle->bus,
+ uci_client->out_attr.mhi_handle->slot,
"_pipe_",
- uci_client->out_chan);
+ uci_client->out_attr.chan_id);
if (IS_ERR(uci_client->dev)) {
uci_log(uci_client->uci_ipc_log,
UCI_DBG_ERROR,
@@ -1427,8 +1426,8 @@ static int mhi_uci_remove(struct platform_device *pdev)
uci_client->uci_ctxt = uci_ctxt;
if (uci_client->in_attr.uci_ownership) {
- mhi_deregister_channel(uci_client->out_handle);
- mhi_deregister_channel(uci_client->in_handle);
+ mhi_deregister_channel(uci_client->out_attr.mhi_handle);
+ mhi_deregister_channel(uci_client->in_attr.mhi_handle);
cdev_del(&uci_ctxt->cdev[i]);
device_destroy(mhi_uci_drv_ctxt.mhi_uci_class,
MKDEV(MAJOR(uci_ctxt->dev_t), i));
diff --git a/drivers/platform/msm/msm_11ad/msm_11ad.c b/drivers/platform/msm/msm_11ad/msm_11ad.c
index 9b48282c812c..c6009d767db5 100644
--- a/drivers/platform/msm/msm_11ad/msm_11ad.c
+++ b/drivers/platform/msm/msm_11ad/msm_11ad.c
@@ -36,7 +36,7 @@
#define WIGIG_VENDOR (0x1ae9)
#define WIGIG_DEVICE (0x0310)
-#define SMMU_BASE 0x10000000 /* Device address range base */
+#define SMMU_BASE 0x20000000 /* Device address range base */
#define SMMU_SIZE ((SZ_1G * 4ULL) - SMMU_BASE)
#define WIGIG_ENABLE_DELAY 50
@@ -93,9 +93,12 @@ struct msm11ad_ctx {
/* SMMU */
bool use_smmu; /* have SMMU enabled? */
- int smmu_bypass;
+ int smmu_s1_en;
int smmu_fast_map;
+ int smmu_coherent;
struct dma_iommu_mapping *mapping;
+ u32 smmu_base;
+ u32 smmu_size;
/* bus frequency scaling */
struct msm_bus_scale_pdata *bus_scale;
@@ -638,15 +641,17 @@ static int msm_11ad_smmu_init(struct msm11ad_ctx *ctx)
{
int atomic_ctx = 1;
int rc;
+ int force_pt_coherent = 1;
+ int smmu_bypass = !ctx->smmu_s1_en;
if (!ctx->use_smmu)
return 0;
- dev_info(ctx->dev, "Initialize SMMU, bypass = %d, fastmap = %d\n",
- ctx->smmu_bypass, ctx->smmu_fast_map);
+ dev_info(ctx->dev, "Initialize SMMU, bypass=%d, fastmap=%d, coherent=%d\n",
+ smmu_bypass, ctx->smmu_fast_map, ctx->smmu_coherent);
ctx->mapping = arm_iommu_create_mapping(&platform_bus_type,
- SMMU_BASE, SMMU_SIZE);
+ ctx->smmu_base, ctx->smmu_size);
if (IS_ERR_OR_NULL(ctx->mapping)) {
rc = PTR_ERR(ctx->mapping) ?: -ENODEV;
dev_err(ctx->dev, "Failed to create IOMMU mapping (%d)\n", rc);
@@ -662,23 +667,39 @@ static int msm_11ad_smmu_init(struct msm11ad_ctx *ctx)
goto release_mapping;
}
- if (ctx->smmu_bypass) {
+ if (smmu_bypass) {
rc = iommu_domain_set_attr(ctx->mapping->domain,
DOMAIN_ATTR_S1_BYPASS,
- &ctx->smmu_bypass);
+ &smmu_bypass);
if (rc) {
dev_err(ctx->dev, "Set bypass attribute to SMMU failed (%d)\n",
rc);
goto release_mapping;
}
- } else if (ctx->smmu_fast_map) {
- rc = iommu_domain_set_attr(ctx->mapping->domain,
- DOMAIN_ATTR_FAST,
- &ctx->smmu_fast_map);
- if (rc) {
- dev_err(ctx->dev, "Set fast attribute to SMMU failed (%d)\n",
- rc);
- goto release_mapping;
+ } else {
+ /* Set dma-coherent and page table coherency */
+ if (ctx->smmu_coherent) {
+ arch_setup_dma_ops(&ctx->pcidev->dev, 0, 0, NULL, true);
+ rc = iommu_domain_set_attr(ctx->mapping->domain,
+ DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT,
+ &force_pt_coherent);
+ if (rc) {
+ dev_err(ctx->dev,
+ "Set SMMU PAGE_TABLE_FORCE_COHERENT attr failed (%d)\n",
+ rc);
+ goto release_mapping;
+ }
+ }
+
+ if (ctx->smmu_fast_map) {
+ rc = iommu_domain_set_attr(ctx->mapping->domain,
+ DOMAIN_ATTR_FAST,
+ &ctx->smmu_fast_map);
+ if (rc) {
+ dev_err(ctx->dev, "Set fast attribute to SMMU failed (%d)\n",
+ rc);
+ goto release_mapping;
+ }
}
}
@@ -729,6 +750,25 @@ static int msm_11ad_ssr_powerup(const struct subsys_desc *subsys)
return rc;
}
+static int msm_11ad_ssr_copy_ramdump(struct msm11ad_ctx *ctx)
+{
+ if (ctx->rops.ramdump && ctx->wil_handle) {
+ int rc = ctx->rops.ramdump(ctx->wil_handle, ctx->ramdump_addr,
+ WIGIG_RAMDUMP_SIZE);
+ if (rc) {
+ dev_err(ctx->dev, "ramdump failed : %d\n", rc);
+ return -EINVAL;
+ }
+ }
+
+ ctx->dump_data.version = WIGIG_DUMP_FORMAT_VER;
+ strlcpy(ctx->dump_data.name, WIGIG_SUBSYS_NAME,
+ sizeof(ctx->dump_data.name));
+
+ ctx->dump_data.magic = WIGIG_DUMP_MAGIC_VER_V1;
+ return 0;
+}
+
static int msm_11ad_ssr_ramdump(int enable, const struct subsys_desc *subsys)
{
int rc;
@@ -745,13 +785,10 @@ static int msm_11ad_ssr_ramdump(int enable, const struct subsys_desc *subsys)
if (!enable)
return 0;
- if (ctx->rops.ramdump && ctx->wil_handle) {
- rc = ctx->rops.ramdump(ctx->wil_handle, ctx->ramdump_addr,
- WIGIG_RAMDUMP_SIZE);
- if (rc) {
- dev_err(ctx->dev, "ramdump failed : %d\n", rc);
- return -EINVAL;
- }
+ if (!ctx->recovery_in_progress) {
+ rc = msm_11ad_ssr_copy_ramdump(ctx);
+ if (rc)
+ return rc;
}
memset(&segment, 0, sizeof(segment));
@@ -763,7 +800,6 @@ static int msm_11ad_ssr_ramdump(int enable, const struct subsys_desc *subsys)
static void msm_11ad_ssr_crash_shutdown(const struct subsys_desc *subsys)
{
- int rc;
struct platform_device *pdev;
struct msm11ad_ctx *ctx;
@@ -775,19 +811,8 @@ static void msm_11ad_ssr_crash_shutdown(const struct subsys_desc *subsys)
return;
}
- if (ctx->rops.ramdump && ctx->wil_handle) {
- rc = ctx->rops.ramdump(ctx->wil_handle, ctx->ramdump_addr,
- WIGIG_RAMDUMP_SIZE);
- if (rc)
- dev_err(ctx->dev, "ramdump failed : %d\n", rc);
- /* continue */
- }
-
- ctx->dump_data.version = WIGIG_DUMP_FORMAT_VER;
- strlcpy(ctx->dump_data.name, WIGIG_SUBSYS_NAME,
- sizeof(ctx->dump_data.name));
-
- ctx->dump_data.magic = WIGIG_DUMP_MAGIC_VER_V1;
+ if (!ctx->recovery_in_progress)
+ (void)msm_11ad_ssr_copy_ramdump(ctx);
}
static void msm_11ad_ssr_deinit(struct msm11ad_ctx *ctx)
@@ -900,6 +925,7 @@ static int msm_11ad_probe(struct platform_device *pdev)
struct device_node *of_node = dev->of_node;
struct device_node *rc_node;
struct pci_dev *pcidev = NULL;
+ u32 smmu_mapping[2];
int rc;
u32 val;
@@ -954,8 +980,27 @@ static int msm_11ad_probe(struct platform_device *pdev)
ctx->use_smmu = of_property_read_bool(of_node, "qcom,smmu-support");
ctx->bus_scale = msm_bus_cl_get_pdata(pdev);
- ctx->smmu_bypass = 1;
- ctx->smmu_fast_map = 0;
+ ctx->smmu_s1_en = of_property_read_bool(of_node, "qcom,smmu-s1-en");
+ if (ctx->smmu_s1_en) {
+ ctx->smmu_fast_map = of_property_read_bool(
+ of_node, "qcom,smmu-fast-map");
+ ctx->smmu_coherent = of_property_read_bool(
+ of_node, "qcom,smmu-coherent");
+ }
+ rc = of_property_read_u32_array(dev->of_node, "qcom,smmu-mapping",
+ smmu_mapping, 2);
+ if (rc) {
+ dev_err(ctx->dev,
+ "Failed to read base/size smmu addresses %d, fallback to default\n",
+ rc);
+ ctx->smmu_base = SMMU_BASE;
+ ctx->smmu_size = SMMU_SIZE;
+ } else {
+ ctx->smmu_base = smmu_mapping[0];
+ ctx->smmu_size = smmu_mapping[1];
+ }
+ dev_dbg(ctx->dev, "smmu_base=0x%x smmu_sise=0x%x\n",
+ ctx->smmu_base, ctx->smmu_size);
/*== execute ==*/
/* turn device on */
@@ -1264,6 +1309,7 @@ static int msm_11ad_notify_crash(struct msm11ad_ctx *ctx)
if (ctx->subsys) {
dev_info(ctx->dev, "SSR requested\n");
+ (void)msm_11ad_ssr_copy_ramdump(ctx);
ctx->recovery_in_progress = true;
rc = subsystem_restart_dev(ctx->subsys);
if (rc) {
diff --git a/drivers/platform/msm/msm_ext_display.c b/drivers/platform/msm/msm_ext_display.c
index a35ed1afc720..6f9a13040cd5 100644
--- a/drivers/platform/msm/msm_ext_display.c
+++ b/drivers/platform/msm/msm_ext_display.c
@@ -215,7 +215,8 @@ static int msm_ext_disp_process_display(struct msm_ext_disp *ext_disp,
{
int ret = 0;
- if (!(flags & MSM_EXT_DISP_HPD_VIDEO)) {
+ if (!(flags & (MSM_EXT_DISP_HPD_VIDEO
+ | MSM_EXT_DISP_HPD_ASYNC_VIDEO))) {
pr_debug("skipping video setup for display (%s)\n",
msm_ext_disp_name(type));
goto end;
@@ -224,7 +225,8 @@ static int msm_ext_disp_process_display(struct msm_ext_disp *ext_disp,
ret = msm_ext_disp_send_cable_notification(ext_disp, state);
/* positive ret value means audio node was switched */
- if (IS_ERR_VALUE(ret) || !ret) {
+ if ((ret <= 0) ||
+ (flags & MSM_EXT_DISP_HPD_ASYNC_VIDEO)) {
pr_debug("not waiting for display\n");
goto end;
}
@@ -237,9 +239,8 @@ static int msm_ext_disp_process_display(struct msm_ext_disp *ext_disp,
goto end;
}
- ret = 0;
end:
- return ret;
+ return (ret >= 0) ? 0 : -EINVAL;
}
static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp,
@@ -248,7 +249,8 @@ static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp,
{
int ret = 0;
- if (!(flags & MSM_EXT_DISP_HPD_AUDIO)) {
+ if (!(flags & (MSM_EXT_DISP_HPD_AUDIO
+ | MSM_EXT_DISP_HPD_ASYNC_AUDIO))) {
pr_debug("skipping audio setup for display (%s)\n",
msm_ext_disp_name(type));
goto end;
@@ -257,7 +259,8 @@ static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp,
ret = msm_ext_disp_send_audio_notification(ext_disp, state);
/* positive ret value means audio node was switched */
- if (IS_ERR_VALUE(ret) || !ret || !ext_disp->ack_enabled) {
+ if ((ret <= 0) || !ext_disp->ack_enabled ||
+ (flags & MSM_EXT_DISP_HPD_ASYNC_AUDIO)) {
pr_debug("not waiting for audio\n");
goto end;
}
@@ -270,9 +273,8 @@ static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp,
goto end;
}
- ret = 0;
end:
- return ret;
+ return (ret >= 0) ? 0 : -EINVAL;
}
static bool msm_ext_disp_validate_connect(struct msm_ext_disp *ext_disp,
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 201a53e66ef0..438da2c51dd6 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -264,6 +264,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(dp_dm),
POWER_SUPPLY_ATTR(input_current_limited),
POWER_SUPPLY_ATTR(input_current_now),
+ POWER_SUPPLY_ATTR(charge_qnovo_enable),
POWER_SUPPLY_ATTR(current_qnovo),
POWER_SUPPLY_ATTR(voltage_qnovo),
POWER_SUPPLY_ATTR(rerun_aicl),
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index 1c0eecdf162c..f2047592a94b 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -46,10 +46,13 @@
&& (value) <= (right)))
/* Awake votable reasons */
-#define SRAM_READ "fg_sram_read"
-#define SRAM_WRITE "fg_sram_write"
-#define PROFILE_LOAD "fg_profile_load"
-#define DELTA_SOC "fg_delta_soc"
+#define SRAM_READ "fg_sram_read"
+#define SRAM_WRITE "fg_sram_write"
+#define PROFILE_LOAD "fg_profile_load"
+#define DELTA_SOC "fg_delta_soc"
+
+/* Delta BSOC votable reasons */
+#define DELTA_BSOC_IRQ_VOTER "fg_delta_bsoc_irq"
#define DEBUG_PRINT_BUFFER_SIZE 64
/* 3 byte address + 1 space character */
@@ -330,6 +333,7 @@ struct fg_chip {
struct fg_memif *sram;
struct fg_irq_info *irqs;
struct votable *awake_votable;
+ struct votable *delta_bsoc_irq_en_votable;
struct fg_sram_param *sp;
struct fg_alg_flag *alg_flags;
int *debug_mask;
@@ -370,8 +374,8 @@ struct fg_chip {
bool esr_fcc_ctrl_en;
bool soc_reporting_ready;
bool esr_flt_cold_temp_en;
- bool bsoc_delta_irq_en;
bool slope_limit_en;
+ bool use_ima_single_mode;
struct completion soc_update;
struct completion soc_ready;
struct delayed_work profile_load_work;
diff --git a/drivers/power/supply/qcom/fg-memif.c b/drivers/power/supply/qcom/fg-memif.c
index 2dc76182ed15..8a949bfe61d0 100644
--- a/drivers/power/supply/qcom/fg-memif.c
+++ b/drivers/power/supply/qcom/fg-memif.c
@@ -48,6 +48,10 @@ static int fg_config_access_mode(struct fg_chip *chip, bool access, bool burst)
int rc;
u8 intf_ctl = 0;
+ fg_dbg(chip, FG_SRAM_READ | FG_SRAM_WRITE, "access: %d burst: %d\n",
+ access, burst);
+
+ WARN_ON(burst && chip->use_ima_single_mode);
intf_ctl = ((access == FG_WRITE) ? IMA_WR_EN_BIT : 0) |
(burst ? MEM_ACS_BURST_BIT : 0);
@@ -175,6 +179,7 @@ int fg_clear_dma_errors_if_any(struct fg_chip *chip)
{
int rc;
u8 dma_sts;
+ bool error_present;
rc = fg_read(chip, MEM_IF_DMA_STS(chip), &dma_sts, 1);
if (rc < 0) {
@@ -184,14 +189,13 @@ int fg_clear_dma_errors_if_any(struct fg_chip *chip)
}
fg_dbg(chip, FG_STATUS, "dma_sts: %x\n", dma_sts);
- if (dma_sts & (DMA_WRITE_ERROR_BIT | DMA_READ_ERROR_BIT)) {
- rc = fg_masked_write(chip, MEM_IF_DMA_CTL(chip),
- DMA_CLEAR_LOG_BIT, DMA_CLEAR_LOG_BIT);
- if (rc < 0) {
- pr_err("failed to write addr=0x%04x, rc=%d\n",
- MEM_IF_DMA_CTL(chip), rc);
- return rc;
- }
+ error_present = dma_sts & (DMA_WRITE_ERROR_BIT | DMA_READ_ERROR_BIT);
+ rc = fg_masked_write(chip, MEM_IF_DMA_CTL(chip), DMA_CLEAR_LOG_BIT,
+ error_present ? DMA_CLEAR_LOG_BIT : 0);
+ if (rc < 0) {
+ pr_err("failed to write addr=0x%04x, rc=%d\n",
+ MEM_IF_DMA_CTL(chip), rc);
+ return rc;
}
return 0;
@@ -293,7 +297,9 @@ static int fg_check_iacs_ready(struct fg_chip *chip)
/* check for error condition */
rc = fg_clear_ima_errors_if_any(chip, false);
if (rc < 0) {
- pr_err("Failed to check for ima errors rc=%d\n", rc);
+ if (rc != -EAGAIN)
+ pr_err("Failed to check for ima errors rc=%d\n",
+ rc);
return rc;
}
@@ -357,7 +363,12 @@ static int __fg_interleaved_mem_write(struct fg_chip *chip, u16 address,
/* check for error condition */
rc = fg_clear_ima_errors_if_any(chip, false);
if (rc < 0) {
- pr_err("Failed to check for ima errors rc=%d\n", rc);
+ if (rc == -EAGAIN)
+ pr_err("IMA error cleared, address [%d %d] len %d\n",
+ address, offset, len);
+ else
+ pr_err("Failed to check for ima errors rc=%d\n",
+ rc);
return rc;
}
@@ -365,6 +376,15 @@ static int __fg_interleaved_mem_write(struct fg_chip *chip, u16 address,
len -= num_bytes;
offset = byte_enable = 0;
+ if (chip->use_ima_single_mode && len) {
+ address++;
+ rc = fg_set_address(chip, address);
+ if (rc < 0) {
+ pr_err("failed to set address rc = %d\n", rc);
+ return rc;
+ }
+ }
+
rc = fg_check_iacs_ready(chip);
if (rc < 0) {
pr_debug("IACS_RDY failed rc=%d\n", rc);
@@ -403,22 +423,40 @@ static int __fg_interleaved_mem_read(struct fg_chip *chip, u16 address,
/* check for error condition */
rc = fg_clear_ima_errors_if_any(chip, false);
if (rc < 0) {
- pr_err("Failed to check for ima errors rc=%d\n", rc);
+ if (rc == -EAGAIN)
+ pr_err("IMA error cleared, address [%d %d] len %d\n",
+ address, offset, len);
+ else
+ pr_err("Failed to check for ima errors rc=%d\n",
+ rc);
return rc;
}
- if (len && len < BYTES_PER_SRAM_WORD) {
- /*
- * Move to single mode. Changing address is not
- * required here as it must be in burst mode. Address
- * will get incremented internally by FG HW once the MSB
- * of RD_DATA is read.
- */
- rc = fg_config_access_mode(chip, FG_READ, 0);
- if (rc < 0) {
- pr_err("failed to move to single mode rc=%d\n",
- rc);
- return -EIO;
+ if (chip->use_ima_single_mode) {
+ if (len) {
+ address++;
+ rc = fg_set_address(chip, address);
+ if (rc < 0) {
+ pr_err("failed to set address rc = %d\n",
+ rc);
+ return rc;
+ }
+ }
+ } else {
+ if (len && len < BYTES_PER_SRAM_WORD) {
+ /*
+ * Move to single mode. Changing address is not
+ * required here as it must be in burst mode.
+ * Address will get incremented internally by FG
+ * HW once the MSB of RD_DATA is read.
+ */
+ rc = fg_config_access_mode(chip, FG_READ,
+ false);
+ if (rc < 0) {
+ pr_err("failed to move to single mode rc=%d\n",
+ rc);
+ return -EIO;
+ }
}
}
@@ -489,6 +527,7 @@ static int fg_interleaved_mem_config(struct fg_chip *chip, u8 *val,
u16 address, int offset, int len, bool access)
{
int rc = 0;
+ bool burst_mode = false;
if (!is_mem_access_available(chip, access))
return -EBUSY;
@@ -503,7 +542,8 @@ static int fg_interleaved_mem_config(struct fg_chip *chip, u8 *val,
}
/* configure for the read/write, single/burst mode */
- rc = fg_config_access_mode(chip, access, (offset + len) > 4);
+ burst_mode = chip->use_ima_single_mode ? false : ((offset + len) > 4);
+ rc = fg_config_access_mode(chip, access, burst_mode);
if (rc < 0) {
pr_err("failed to set memory access rc = %d\n", rc);
return rc;
@@ -583,7 +623,7 @@ retry:
if (rc < 0) {
count++;
if (rc == -EAGAIN) {
- pr_err("IMA access failed retry_count = %d\n", count);
+ pr_err("IMA read failed retry_count = %d\n", count);
goto retry;
}
pr_err("failed to read SRAM address rc = %d\n", rc);
@@ -667,8 +707,8 @@ retry:
rc = __fg_interleaved_mem_write(chip, address, offset, val, len);
if (rc < 0) {
count++;
- if ((rc == -EAGAIN) && (count < RETRY_COUNT)) {
- pr_err("IMA access failed retry_count = %d\n", count);
+ if (rc == -EAGAIN) {
+ pr_err("IMA write failed retry_count = %d\n", count);
goto retry;
}
pr_err("failed to write SRAM address rc = %d\n", rc);
diff --git a/drivers/power/supply/qcom/pmic-voter.c b/drivers/power/supply/qcom/pmic-voter.c
index 3652cc7802eb..b99558ed2100 100644
--- a/drivers/power/supply/qcom/pmic-voter.c
+++ b/drivers/power/supply/qcom/pmic-voter.c
@@ -20,7 +20,7 @@
#include <linux/pmic-voter.h>
-#define NUM_MAX_CLIENTS 8
+#define NUM_MAX_CLIENTS 16
#define DEBUG_FORCE_CLIENT "DEBUG_FORCE_CLIENT"
static DEFINE_SPINLOCK(votable_list_slock);
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 5dcd4c36675a..59216a567662 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -525,7 +525,7 @@ static int fg_get_sram_prop(struct fg_chip *chip, enum fg_sram_param_id id,
}
#define CC_SOC_30BIT GENMASK(29, 0)
-static int fg_get_cc_soc(struct fg_chip *chip, int *val)
+static int fg_get_charge_raw(struct fg_chip *chip, int *val)
{
int rc, cc_soc;
@@ -539,7 +539,7 @@ static int fg_get_cc_soc(struct fg_chip *chip, int *val)
return 0;
}
-static int fg_get_cc_soc_sw(struct fg_chip *chip, int *val)
+static int fg_get_charge_counter(struct fg_chip *chip, int *val)
{
int rc, cc_soc;
@@ -1054,6 +1054,25 @@ static void fg_notify_charger(struct fg_chip *chip)
fg_dbg(chip, FG_STATUS, "Notified charger on float voltage and FCC\n");
}
+static int fg_delta_bsoc_irq_en_cb(struct votable *votable, void *data,
+ int enable, const char *client)
+{
+ struct fg_chip *chip = data;
+
+ if (!chip->irqs[BSOC_DELTA_IRQ].irq)
+ return 0;
+
+ if (enable) {
+ enable_irq(chip->irqs[BSOC_DELTA_IRQ].irq);
+ enable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq);
+ } else {
+ disable_irq_wake(chip->irqs[BSOC_DELTA_IRQ].irq);
+ disable_irq(chip->irqs[BSOC_DELTA_IRQ].irq);
+ }
+
+ return 0;
+}
+
static int fg_awake_cb(struct votable *votable, void *data, int awake,
const char *client)
{
@@ -1241,7 +1260,7 @@ static void fg_cap_learning_post_process(struct fg_chip *chip)
chip->cl.final_cc_uah, old_cap, chip->cl.learned_cc_uah);
}
-static int fg_cap_learning_process_full_data(struct fg_chip *chip)
+static int fg_cap_learning_process_full_data(struct fg_chip *chip)
{
int rc, cc_soc_sw, cc_soc_delta_pct;
int64_t delta_cc_uah;
@@ -1263,30 +1282,39 @@ static int fg_cap_learning_process_full_data(struct fg_chip *chip)
return 0;
}
-static int fg_cap_learning_begin(struct fg_chip *chip, int batt_soc)
+#define BATT_SOC_32BIT GENMASK(31, 0)
+static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)
{
- int rc, cc_soc_sw;
+ int rc, cc_soc_sw, batt_soc_msb;
- if (DIV_ROUND_CLOSEST(batt_soc * 100, FULL_SOC_RAW) >
+ batt_soc_msb = batt_soc >> 24;
+ if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) >
chip->dt.cl_start_soc) {
fg_dbg(chip, FG_CAP_LEARN, "Battery SOC %d is high!, not starting\n",
- batt_soc);
+ batt_soc_msb);
return -EINVAL;
}
- chip->cl.init_cc_uah = div64_s64(chip->cl.learned_cc_uah * batt_soc,
+ chip->cl.init_cc_uah = div64_s64(chip->cl.learned_cc_uah * batt_soc_msb,
FULL_SOC_RAW);
- rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc_sw);
+
+ /* Prime cc_soc_sw with battery SOC when capacity learning begins */
+ cc_soc_sw = div64_s64((int64_t)batt_soc * CC_SOC_30BIT,
+ BATT_SOC_32BIT);
+ rc = fg_sram_write(chip, chip->sp[FG_SRAM_CC_SOC_SW].addr_word,
+ chip->sp[FG_SRAM_CC_SOC_SW].addr_byte, (u8 *)&cc_soc_sw,
+ chip->sp[FG_SRAM_CC_SOC_SW].len, FG_IMA_ATOMIC);
if (rc < 0) {
- pr_err("Error in getting CC_SOC_SW, rc=%d\n", rc);
- return rc;
+ pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
+ goto out;
}
chip->cl.init_cc_soc_sw = cc_soc_sw;
chip->cl.active = true;
fg_dbg(chip, FG_CAP_LEARN, "Capacity learning started @ battery SOC %d init_cc_soc_sw:%d\n",
- batt_soc, chip->cl.init_cc_soc_sw);
- return 0;
+ batt_soc_msb, chip->cl.init_cc_soc_sw);
+out:
+ return rc;
}
static int fg_cap_learning_done(struct fg_chip *chip)
@@ -1318,7 +1346,7 @@ out:
#define FULL_SOC_RAW 255
static void fg_cap_learning_update(struct fg_chip *chip)
{
- int rc, batt_soc;
+ int rc, batt_soc, batt_soc_msb;
mutex_lock(&chip->cl.lock);
@@ -1337,11 +1365,9 @@ static void fg_cap_learning_update(struct fg_chip *chip)
goto out;
}
- /* We need only the most significant byte here */
- batt_soc = (u32)batt_soc >> 24;
-
+ batt_soc_msb = (u32)batt_soc >> 24;
fg_dbg(chip, FG_CAP_LEARN, "Chg_status: %d cl_active: %d batt_soc: %d\n",
- chip->charge_status, chip->cl.active, batt_soc);
+ chip->charge_status, chip->cl.active, batt_soc_msb);
/* Initialize the starting point of learning capacity */
if (!chip->cl.active) {
@@ -1363,7 +1389,7 @@ static void fg_cap_learning_update(struct fg_chip *chip)
if (chip->charge_status == POWER_SUPPLY_STATUS_NOT_CHARGING) {
fg_dbg(chip, FG_CAP_LEARN, "Capacity learning aborted @ battery SOC %d\n",
- batt_soc);
+ batt_soc_msb);
chip->cl.active = false;
chip->cl.init_cc_uah = 0;
}
@@ -1470,16 +1496,8 @@ static int fg_charge_full_update(struct fg_chip *chip)
return 0;
mutex_lock(&chip->charge_full_lock);
- if (!chip->charge_done && chip->bsoc_delta_irq_en) {
- disable_irq_wake(fg_irqs[BSOC_DELTA_IRQ].irq);
- disable_irq_nosync(fg_irqs[BSOC_DELTA_IRQ].irq);
- chip->bsoc_delta_irq_en = false;
- } else if (chip->charge_done && !chip->bsoc_delta_irq_en) {
- enable_irq(fg_irqs[BSOC_DELTA_IRQ].irq);
- enable_irq_wake(fg_irqs[BSOC_DELTA_IRQ].irq);
- chip->bsoc_delta_irq_en = true;
- }
-
+ vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER,
+ chip->charge_done, 0);
rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
&prop);
if (rc < 0) {
@@ -1598,6 +1616,9 @@ static int fg_rconn_config(struct fg_chip *chip)
u64 scaling_factor;
u32 val = 0;
+ if (!chip->dt.rconn_mohms)
+ return 0;
+
rc = fg_sram_read(chip, PROFILE_INTEGRITY_WORD,
SW_CONFIG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT);
if (rc < 0) {
@@ -2188,6 +2209,17 @@ static bool is_profile_load_required(struct fg_chip *chip)
/* Check if integrity bit is set */
if (val & PROFILE_LOAD_BIT) {
fg_dbg(chip, FG_STATUS, "Battery profile integrity bit is set\n");
+
+ /* Whitelist the values */
+ val &= ~PROFILE_LOAD_BIT;
+ if (val != HLOS_RESTART_BIT && val != BOOTLOADER_LOAD_BIT &&
+ val != (BOOTLOADER_LOAD_BIT | BOOTLOADER_RESTART_BIT)) {
+ val |= PROFILE_LOAD_BIT;
+ pr_warn("Garbage value in profile integrity word: 0x%x\n",
+ val);
+ return true;
+ }
+
rc = fg_sram_read(chip, PROFILE_LOAD_WORD, PROFILE_LOAD_OFFSET,
buf, PROFILE_COMP_LEN, FG_IMA_DEFAULT);
if (rc < 0) {
@@ -2818,7 +2850,7 @@ static int fg_psy_get_property(struct power_supply *psy,
pval->intval = chip->cyc_ctr.id;
break;
case POWER_SUPPLY_PROP_CHARGE_NOW_RAW:
- rc = fg_get_cc_soc(chip, &pval->intval);
+ rc = fg_get_charge_raw(chip, &pval->intval);
break;
case POWER_SUPPLY_PROP_CHARGE_NOW:
pval->intval = chip->cl.init_cc_uah;
@@ -2827,7 +2859,7 @@ static int fg_psy_get_property(struct power_supply *psy,
pval->intval = chip->cl.learned_cc_uah;
break;
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
- rc = fg_get_cc_soc_sw(chip, &pval->intval);
+ rc = fg_get_charge_counter(chip, &pval->intval);
break;
case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
rc = fg_get_time_to_full(chip, &pval->intval);
@@ -3176,12 +3208,10 @@ static int fg_hw_init(struct fg_chip *chip)
return rc;
}
- if (chip->dt.rconn_mohms > 0) {
- rc = fg_rconn_config(chip);
- if (rc < 0) {
- pr_err("Error in configuring Rconn, rc=%d\n", rc);
- return rc;
- }
+ rc = fg_rconn_config(chip);
+ if (rc < 0) {
+ pr_err("Error in configuring Rconn, rc=%d\n", rc);
+ return rc;
}
fg_encode(chip->sp, FG_SRAM_ESR_TIGHT_FILTER,
@@ -3228,20 +3258,19 @@ static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
}
fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status);
- if (status & MEM_XCP_BIT) {
- rc = fg_clear_dma_errors_if_any(chip);
- if (rc < 0) {
- pr_err("Error in clearing DMA error, rc=%d\n", rc);
- return IRQ_HANDLED;
- }
- mutex_lock(&chip->sram_rw_lock);
+ mutex_lock(&chip->sram_rw_lock);
+ rc = fg_clear_dma_errors_if_any(chip);
+ if (rc < 0)
+ pr_err("Error in clearing DMA error, rc=%d\n", rc);
+
+ if (status & MEM_XCP_BIT) {
rc = fg_clear_ima_errors_if_any(chip, true);
if (rc < 0 && rc != -EAGAIN)
pr_err("Error in checking IMA errors rc:%d\n", rc);
- mutex_unlock(&chip->sram_rw_lock);
}
+ mutex_unlock(&chip->sram_rw_lock);
return IRQ_HANDLED;
}
@@ -3737,6 +3766,7 @@ static int fg_parse_dt(struct fg_chip *chip)
case PM660_SUBTYPE:
chip->sp = pmi8998_v2_sram_params;
chip->alg_flags = pmi8998_v2_alg_flags;
+ chip->use_ima_single_mode = true;
break;
default:
return -EINVAL;
@@ -3957,9 +3987,7 @@ static int fg_parse_dt(struct fg_chip *chip)
pr_err("Error in parsing Ki coefficients, rc=%d\n", rc);
rc = of_property_read_u32(node, "qcom,fg-rconn-mohms", &temp);
- if (rc < 0)
- chip->dt.rconn_mohms = -EINVAL;
- else
+ if (!rc)
chip->dt.rconn_mohms = temp;
rc = of_property_read_u32(node, "qcom,fg-esr-filter-switch-temp",
@@ -4017,6 +4045,9 @@ static void fg_cleanup(struct fg_chip *chip)
if (chip->awake_votable)
destroy_votable(chip->awake_votable);
+ if (chip->delta_bsoc_irq_en_votable)
+ destroy_votable(chip->delta_bsoc_irq_en_votable);
+
if (chip->batt_id_chan)
iio_channel_release(chip->batt_id_chan);
@@ -4058,7 +4089,15 @@ static int fg_gen3_probe(struct platform_device *pdev)
chip);
if (IS_ERR(chip->awake_votable)) {
rc = PTR_ERR(chip->awake_votable);
- return rc;
+ goto exit;
+ }
+
+ chip->delta_bsoc_irq_en_votable = create_votable("FG_DELTA_BSOC_IRQ",
+ VOTE_SET_ANY,
+ fg_delta_bsoc_irq_en_cb, chip);
+ if (IS_ERR(chip->delta_bsoc_irq_en_votable)) {
+ rc = PTR_ERR(chip->delta_bsoc_irq_en_votable);
+ goto exit;
}
rc = fg_parse_dt(chip);
@@ -4085,7 +4124,7 @@ static int fg_gen3_probe(struct platform_device *pdev)
rc = fg_get_batt_id(chip);
if (rc < 0) {
pr_err("Error in getting battery id, rc:%d\n", rc);
- return rc;
+ goto exit;
}
rc = fg_get_batt_profile(chip);
@@ -4143,11 +4182,7 @@ static int fg_gen3_probe(struct platform_device *pdev)
disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq);
/* Keep BSOC_DELTA_IRQ irq disabled until we require it */
- if (fg_irqs[BSOC_DELTA_IRQ].irq) {
- disable_irq_wake(fg_irqs[BSOC_DELTA_IRQ].irq);
- disable_irq_nosync(fg_irqs[BSOC_DELTA_IRQ].irq);
- chip->bsoc_delta_irq_en = false;
- }
+ rerun_election(chip->delta_bsoc_irq_en_votable);
rc = fg_debugfs_create(chip);
if (rc < 0) {
diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c
index 712f37daa1ca..c74dc8989821 100644
--- a/drivers/power/supply/qcom/qpnp-qnovo.c
+++ b/drivers/power/supply/qcom/qpnp-qnovo.c
@@ -29,6 +29,8 @@
#define QNOVO_PTRAIN_STS 0x08
#define QNOVO_ERROR_STS 0x09
#define QNOVO_ERROR_BIT BIT(0)
+#define QNOVO_ERROR_STS2 0x0A
+#define QNOVO_ERROR_CHARGING_DISABLED BIT(1)
#define QNOVO_INT_RT_STS 0x10
#define QNOVO_INT_SET_TYPE 0x11
#define QNOVO_INT_POLARITY_HIGH 0x12
@@ -109,20 +111,6 @@ struct qnovo_dt_props {
struct device_node *revid_dev_node;
};
-enum {
- QNOVO_NO_ERR_STS_BIT = BIT(0),
-};
-
-struct chg_props {
- bool charging;
- bool usb_online;
- bool dc_online;
-};
-
-struct chg_status {
- bool ok_to_qnovo;
-};
-
struct qnovo {
int base;
struct mutex write_lock;
@@ -141,17 +129,14 @@ struct qnovo {
s64 v_gain_mega;
struct notifier_block nb;
struct power_supply *batt_psy;
- struct power_supply *usb_psy;
- struct power_supply *dc_psy;
- struct chg_props cp;
- struct chg_status cs;
struct work_struct status_change_work;
int fv_uV_request;
int fcc_uA_request;
+ bool ok_to_qnovo;
};
static int debug_mask;
-module_param_named(debug_mask, debug_mask, int, S_IRUSR | S_IWUSR);
+module_param_named(debug_mask, debug_mask, int, 0600);
#define qnovo_dbg(chip, reason, fmt, ...) \
do { \
@@ -272,28 +257,22 @@ static int qnovo_disable_cb(struct votable *votable, void *data, int disable,
const char *client)
{
struct qnovo *chip = data;
- int rc = 0;
+ union power_supply_propval pval = {0};
+ int rc;
- if (disable) {
- rc = qnovo_batt_psy_update(chip, true);
- if (rc < 0)
- return rc;
- }
+ if (!is_batt_available(chip))
+ return -EINVAL;
- rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT,
- disable ? 0 : QNOVO_PTRAIN_EN_BIT);
+ pval.intval = !disable;
+ rc = power_supply_set_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE,
+ &pval);
if (rc < 0) {
- dev_err(chip->dev, "Couldn't %s pulse train rc=%d\n",
- disable ? "disable" : "enable", rc);
- return rc;
- }
-
- if (!disable) {
- rc = qnovo_batt_psy_update(chip, false);
- if (rc < 0)
- return rc;
+ pr_err("Couldn't set prop qnovo_enable rc = %d\n", rc);
+ return -EINVAL;
}
+ rc = qnovo_batt_psy_update(chip, disable);
return rc;
}
@@ -325,36 +304,18 @@ static int qnovo_parse_dt(struct qnovo *chip)
return 0;
}
-static int qnovo_check_chg_version(struct qnovo *chip)
-{
- int rc;
-
- chip->pmic_rev_id = get_revid_data(chip->dt.revid_dev_node);
- if (IS_ERR(chip->pmic_rev_id)) {
- rc = PTR_ERR(chip->pmic_rev_id);
- if (rc != -EPROBE_DEFER)
- pr_err("Unable to get pmic_revid rc=%d\n", rc);
- return rc;
- }
-
- if ((chip->pmic_rev_id->pmic_subtype == PMI8998_SUBTYPE)
- && (chip->pmic_rev_id->rev4 < PMI8998_V2P0_REV4)) {
- chip->wa_flags |= QNOVO_NO_ERR_STS_BIT;
- }
-
- return 0;
-}
-
enum {
VER = 0,
OK_TO_QNOVO,
- ENABLE,
+ QNOVO_ENABLE,
+ PT_ENABLE,
FV_REQUEST,
FCC_REQUEST,
PE_CTRL_REG,
PE_CTRL2_REG,
PTRAIN_STS_REG,
INT_RT_STS_REG,
+ ERR_STS2_REG,
PREST1,
PPULS1,
NREST1,
@@ -394,6 +355,12 @@ struct param_info {
};
static struct param_info params[] = {
+ [PT_ENABLE] = {
+ .name = "PT_ENABLE",
+ .start_addr = QNOVO_PTRAIN_EN,
+ .num_regs = 1,
+ .units_str = "",
+ },
[FV_REQUEST] = {
.units_str = "uV",
},
@@ -424,6 +391,12 @@ static struct param_info params[] = {
.num_regs = 1,
.units_str = "",
},
+ [ERR_STS2_REG] = {
+ .name = "RAW_CHGR_ERR",
+ .start_addr = QNOVO_ERROR_STS2,
+ .num_regs = 1,
+ .units_str = "",
+ },
[PREST1] = {
.name = "PREST1",
.start_addr = QNOVO_PREST1_CTRL,
@@ -431,7 +404,7 @@ static struct param_info params[] = {
.reg_to_unit_multiplier = 5,
.reg_to_unit_divider = 1,
.min_val = 5,
- .max_val = 1275,
+ .max_val = 255,
.units_str = "mS",
},
[PPULS1] = {
@@ -440,8 +413,8 @@ static struct param_info params[] = {
.num_regs = 2,
.reg_to_unit_multiplier = 1600, /* converts to uC */
.reg_to_unit_divider = 1,
- .min_val = 0,
- .max_val = 104856000,
+ .min_val = 30000,
+ .max_val = 65535000,
.units_str = "uC",
},
[NREST1] = {
@@ -451,7 +424,7 @@ static struct param_info params[] = {
.reg_to_unit_multiplier = 5,
.reg_to_unit_divider = 1,
.min_val = 5,
- .max_val = 1275,
+ .max_val = 255,
.units_str = "mS",
},
[NPULS1] = {
@@ -460,8 +433,8 @@ static struct param_info params[] = {
.num_regs = 1,
.reg_to_unit_multiplier = 5,
.reg_to_unit_divider = 1,
- .min_val = 5,
- .max_val = 1275,
+ .min_val = 0,
+ .max_val = 255,
.units_str = "mS",
},
[PPCNT] = {
@@ -470,7 +443,7 @@ static struct param_info params[] = {
.num_regs = 1,
.reg_to_unit_multiplier = 1,
.reg_to_unit_divider = 1,
- .min_val = 0,
+ .min_val = 1,
.max_val = 255,
.units_str = "pulses",
},
@@ -480,8 +453,8 @@ static struct param_info params[] = {
.num_regs = 2,
.reg_to_unit_multiplier = 610350, /* converts to nV */
.reg_to_unit_divider = 1,
- .min_val = 0,
- .max_val = 5000000,
+ .min_val = 2200000,
+ .max_val = 4500000,
.units_str = "uV",
},
[PVOLT1] = {
@@ -506,8 +479,6 @@ static struct param_info params[] = {
.num_regs = 1,
.reg_to_unit_multiplier = 2,
.reg_to_unit_divider = 1,
- .min_val = 5,
- .max_val = 1275,
.units_str = "S",
},
[PREST2] = {
@@ -517,7 +488,7 @@ static struct param_info params[] = {
.reg_to_unit_multiplier = 5,
.reg_to_unit_divider = 1,
.min_val = 5,
- .max_val = 327675,
+ .max_val = 65535,
.units_str = "mS",
},
[PPULS2] = {
@@ -526,8 +497,8 @@ static struct param_info params[] = {
.num_regs = 2,
.reg_to_unit_multiplier = 1600, /* converts to uC */
.reg_to_unit_divider = 1,
- .min_val = 0,
- .max_val = 104856000,
+ .min_val = 30000,
+ .max_val = 65535000,
.units_str = "uC",
},
[NREST2] = {
@@ -538,7 +509,7 @@ static struct param_info params[] = {
.reg_to_unit_divider = 1,
.reg_to_unit_offset = -5,
.min_val = 5,
- .max_val = 1280,
+ .max_val = 255,
.units_str = "mS",
},
[NPULS2] = {
@@ -547,18 +518,18 @@ static struct param_info params[] = {
.num_regs = 1,
.reg_to_unit_multiplier = 5,
.reg_to_unit_divider = 1,
- .min_val = 5,
- .max_val = 1275,
+ .min_val = 0,
+ .max_val = 255,
.units_str = "mS",
},
[VLIM2] = {
- .name = "VLIM1",
+ .name = "VLIM2",
.start_addr = QNOVO_VLIM2_LSB_CTRL,
.num_regs = 2,
.reg_to_unit_multiplier = 610350, /* converts to nV */
.reg_to_unit_divider = 1,
- .min_val = 0,
- .max_val = 5000000,
+ .min_val = 2200000,
+ .max_val = 4500000,
.units_str = "uV",
},
[PVOLT2] = {
@@ -591,6 +562,8 @@ static struct param_info params[] = {
.num_regs = 1,
.reg_to_unit_multiplier = 1,
.reg_to_unit_divider = 1,
+ .min_val = 0,
+ .max_val = 255,
.units_str = "pulses",
},
[VMAX] = {
@@ -645,33 +618,73 @@ static ssize_t ok_to_qnovo_show(struct class *c, struct class_attribute *attr,
{
struct qnovo *chip = container_of(c, struct qnovo, qnovo_class);
- return snprintf(buf, PAGE_SIZE, "%d\n", chip->cs.ok_to_qnovo);
+ return snprintf(buf, PAGE_SIZE, "%d\n", chip->ok_to_qnovo);
}
-static ssize_t enable_show(struct class *c, struct class_attribute *attr,
+static ssize_t qnovo_enable_show(struct class *c, struct class_attribute *attr,
char *ubuf)
{
struct qnovo *chip = container_of(c, struct qnovo, qnovo_class);
- int val;
+ int val = get_effective_result(chip->disable_votable);
- val = get_client_vote(chip->disable_votable, USER_VOTER);
- val = !val;
- return snprintf(ubuf, PAGE_SIZE, "%d\n", val);
+ return snprintf(ubuf, PAGE_SIZE, "%d\n", !val);
+}
+
+static ssize_t qnovo_enable_store(struct class *c, struct class_attribute *attr,
+ const char *ubuf, size_t count)
+{
+ struct qnovo *chip = container_of(c, struct qnovo, qnovo_class);
+ unsigned long val;
+
+ if (kstrtoul(ubuf, 0, &val))
+ return -EINVAL;
+
+ vote(chip->disable_votable, USER_VOTER, !val, 0);
+
+ return count;
+}
+
+static ssize_t pt_enable_show(struct class *c, struct class_attribute *attr,
+ char *ubuf)
+{
+ int i = attr - qnovo_attributes;
+ struct qnovo *chip = container_of(c, struct qnovo, qnovo_class);
+ u8 buf[2] = {0, 0};
+ u16 regval;
+ int rc;
+
+ rc = qnovo_read(chip, params[i].start_addr, buf, params[i].num_regs);
+ if (rc < 0) {
+ pr_err("Couldn't read %s rc = %d\n", params[i].name, rc);
+ return -EINVAL;
+ }
+ regval = buf[1] << 8 | buf[0];
+
+ return snprintf(ubuf, PAGE_SIZE, "%d\n",
+ (int)(regval & QNOVO_PTRAIN_EN_BIT));
}
-static ssize_t enable_store(struct class *c, struct class_attribute *attr,
+static ssize_t pt_enable_store(struct class *c, struct class_attribute *attr,
const char *ubuf, size_t count)
{
struct qnovo *chip = container_of(c, struct qnovo, qnovo_class);
unsigned long val;
- bool disable;
+ int rc = 0;
- if (kstrtoul(ubuf, 10, &val))
+ if (get_effective_result(chip->disable_votable))
return -EINVAL;
- disable = !val;
+ if (kstrtoul(ubuf, 0, &val))
+ return -EINVAL;
+
+ rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT,
+ (bool)val ? QNOVO_PTRAIN_EN_BIT : 0);
+ if (rc < 0) {
+ dev_err(chip->dev, "Couldn't %s pulse train rc=%d\n",
+ (bool)val ? "enable" : "disable", rc);
+ return rc;
+ }
- vote(chip->disable_votable, USER_VOTER, disable, 0);
return count;
}
@@ -688,7 +701,7 @@ static ssize_t val_show(struct class *c, struct class_attribute *attr,
if (i == FCC_REQUEST)
val = chip->fcc_uA_request;
- return snprintf(ubuf, PAGE_SIZE, "%d%s\n", val, params[i].units_str);
+ return snprintf(ubuf, PAGE_SIZE, "%d\n", val);
}
static ssize_t val_store(struct class *c, struct class_attribute *attr,
@@ -698,7 +711,7 @@ static ssize_t val_store(struct class *c, struct class_attribute *attr,
int i = attr - qnovo_attributes;
unsigned long val;
- if (kstrtoul(ubuf, 10, &val))
+ if (kstrtoul(ubuf, 0, &val))
return -EINVAL;
if (i == FV_REQUEST)
@@ -707,6 +720,9 @@ static ssize_t val_store(struct class *c, struct class_attribute *attr,
if (i == FCC_REQUEST)
chip->fcc_uA_request = val;
+ if (!get_effective_result(chip->disable_votable))
+ qnovo_batt_psy_update(chip, false);
+
return count;
}
@@ -726,8 +742,7 @@ static ssize_t reg_show(struct class *c, struct class_attribute *attr,
}
regval = buf[1] << 8 | buf[0];
- return snprintf(ubuf, PAGE_SIZE, "0x%04x%s\n",
- regval, params[i].units_str);
+ return snprintf(ubuf, PAGE_SIZE, "0x%04x\n", regval);
}
static ssize_t reg_store(struct class *c, struct class_attribute *attr,
@@ -739,7 +754,7 @@ static ssize_t reg_store(struct class *c, struct class_attribute *attr,
unsigned long val;
int rc;
- if (kstrtoul(ubuf, 16, &val))
+ if (kstrtoul(ubuf, 0, &val))
return -EINVAL;
buf[0] = val & 0xFF;
@@ -774,7 +789,7 @@ static ssize_t time_show(struct class *c, struct class_attribute *attr,
/ params[i].reg_to_unit_divider)
- params[i].reg_to_unit_offset;
- return snprintf(ubuf, PAGE_SIZE, "%d%s\n", val, params[i].units_str);
+ return snprintf(ubuf, PAGE_SIZE, "%d\n", val);
}
static ssize_t time_store(struct class *c, struct class_attribute *attr,
@@ -787,7 +802,7 @@ static ssize_t time_store(struct class *c, struct class_attribute *attr,
unsigned long val;
int rc;
- if (kstrtoul(ubuf, 10, &val))
+ if (kstrtoul(ubuf, 0, &val))
return -EINVAL;
if (val < params[i].min_val || val > params[i].max_val) {
@@ -828,7 +843,11 @@ static ssize_t current_show(struct class *c, struct class_attribute *attr,
pr_err("Couldn't read %s rc = %d\n", params[i].name, rc);
return -EINVAL;
}
- regval_nA = buf[1] << 8 | buf[0];
+
+ if (buf[1] & BIT(5))
+ buf[1] |= GENMASK(7, 6);
+
+ regval_nA = (s16)(buf[1] << 8 | buf[0]);
regval_nA = div_s64(regval_nA * params[i].reg_to_unit_multiplier,
params[i].reg_to_unit_divider)
- params[i].reg_to_unit_offset;
@@ -841,11 +860,10 @@ static ssize_t current_show(struct class *c, struct class_attribute *attr,
gain = chip->internal_i_gain_mega;
}
- comp_val_nA = div_s64(regval_nA * gain, 1000000) + offset_nA;
+ comp_val_nA = div_s64(regval_nA * gain, 1000000) - offset_nA;
comp_val_uA = div_s64(comp_val_nA, 1000);
- return snprintf(ubuf, PAGE_SIZE, "%d%s\n",
- comp_val_uA, params[i].units_str);
+ return snprintf(ubuf, PAGE_SIZE, "%d\n", comp_val_uA);
}
static ssize_t voltage_show(struct class *c, struct class_attribute *attr,
@@ -875,8 +893,7 @@ static ssize_t voltage_show(struct class *c, struct class_attribute *attr,
comp_val_nV = div_s64(regval_nV * gain, 1000000) + offset_nV;
comp_val_uV = div_s64(comp_val_nV, 1000);
- return snprintf(ubuf, PAGE_SIZE, "%d%s\n",
- comp_val_uV, params[i].units_str);
+ return snprintf(ubuf, PAGE_SIZE, "%d\n", comp_val_uV);
}
static ssize_t voltage_store(struct class *c, struct class_attribute *attr,
@@ -890,7 +907,7 @@ static ssize_t voltage_store(struct class *c, struct class_attribute *attr,
s64 regval_nV;
s64 gain, offset_nV;
- if (kstrtoul(ubuf, 10, &val_uV))
+ if (kstrtoul(ubuf, 0, &val_uV))
return -EINVAL;
if (val_uV < params[i].min_val || val_uV > params[i].max_val) {
@@ -947,8 +964,7 @@ static ssize_t coulomb_show(struct class *c, struct class_attribute *attr,
gain = chip->internal_i_gain_mega;
comp_val_uC = div_s64(regval_uC * gain, 1000000);
- return snprintf(ubuf, PAGE_SIZE, "%d%s\n",
- comp_val_uC, params[i].units_str);
+ return snprintf(ubuf, PAGE_SIZE, "%d\n", comp_val_uC);
}
static ssize_t coulomb_store(struct class *c, struct class_attribute *attr,
@@ -962,7 +978,7 @@ static ssize_t coulomb_store(struct class *c, struct class_attribute *attr,
s64 regval;
s64 gain;
- if (kstrtoul(ubuf, 10, &val_uC))
+ if (kstrtoul(ubuf, 0, &val_uC))
return -EINVAL;
if (val_uC < params[i].min_val || val_uC > params[i].max_val) {
@@ -1014,167 +1030,113 @@ static ssize_t batt_prop_show(struct class *c, struct class_attribute *attr,
return -EINVAL;
}
- return snprintf(ubuf, PAGE_SIZE, "%d%s\n",
- pval.intval, params[i].units_str);
+ return snprintf(ubuf, PAGE_SIZE, "%d\n", pval.intval);
}
static struct class_attribute qnovo_attributes[] = {
[VER] = __ATTR_RO(version),
[OK_TO_QNOVO] = __ATTR_RO(ok_to_qnovo),
- [ENABLE] = __ATTR(enable, S_IRUGO | S_IWUSR,
- enable_show, enable_store),
- [FV_REQUEST] = __ATTR(fv_uV_request, S_IRUGO | S_IWUSR,
+ [QNOVO_ENABLE] = __ATTR_RW(qnovo_enable),
+ [PT_ENABLE] = __ATTR_RW(pt_enable),
+ [FV_REQUEST] = __ATTR(fv_uV_request, 0644,
val_show, val_store),
- [FCC_REQUEST] = __ATTR(fcc_uA_request, S_IRUGO | S_IWUSR,
+ [FCC_REQUEST] = __ATTR(fcc_uA_request, 0644,
val_show, val_store),
- [PE_CTRL_REG] = __ATTR(PE_CTRL_REG, S_IRUGO | S_IWUSR,
- reg_show, reg_store),
- [PE_CTRL2_REG] = __ATTR(PE_CTRL2_REG, S_IRUGO | S_IWUSR,
- reg_show, reg_store),
- [PTRAIN_STS_REG] = __ATTR(PTRAIN_STS_REG, S_IRUGO | S_IWUSR,
+ [PE_CTRL_REG] = __ATTR(PE_CTRL_REG, 0644,
reg_show, reg_store),
- [INT_RT_STS_REG] = __ATTR(INT_RT_STS_REG, S_IRUGO | S_IWUSR,
+ [PE_CTRL2_REG] = __ATTR(PE_CTRL2_REG, 0644,
reg_show, reg_store),
- [PREST1] = __ATTR(PREST1_mS, S_IRUGO | S_IWUSR,
+ [PTRAIN_STS_REG] = __ATTR(PTRAIN_STS_REG, 0444,
+ reg_show, NULL),
+ [INT_RT_STS_REG] = __ATTR(INT_RT_STS_REG, 0444,
+ reg_show, NULL),
+ [ERR_STS2_REG] = __ATTR(ERR_STS2_REG, 0444,
+ reg_show, NULL),
+ [PREST1] = __ATTR(PREST1_mS, 0644,
time_show, time_store),
- [PPULS1] = __ATTR(PPULS1_uC, S_IRUGO | S_IWUSR,
+ [PPULS1] = __ATTR(PPULS1_uC, 0644,
coulomb_show, coulomb_store),
- [NREST1] = __ATTR(NREST1_mS, S_IRUGO | S_IWUSR,
+ [NREST1] = __ATTR(NREST1_mS, 0644,
time_show, time_store),
- [NPULS1] = __ATTR(NPULS1_mS, S_IRUGO | S_IWUSR,
+ [NPULS1] = __ATTR(NPULS1_mS, 0644,
time_show, time_store),
- [PPCNT] = __ATTR(PPCNT, S_IRUGO | S_IWUSR,
+ [PPCNT] = __ATTR(PPCNT, 0644,
time_show, time_store),
- [VLIM1] = __ATTR(VLIM1_uV, S_IRUGO | S_IWUSR,
+ [VLIM1] = __ATTR(VLIM1_uV, 0644,
voltage_show, voltage_store),
- [PVOLT1] = __ATTR(PVOLT1_uV, S_IRUGO,
+ [PVOLT1] = __ATTR(PVOLT1_uV, 0444,
voltage_show, NULL),
- [PCUR1] = __ATTR(PCUR1_uA, S_IRUGO,
+ [PCUR1] = __ATTR(PCUR1_uA, 0444,
current_show, NULL),
- [PTTIME] = __ATTR(PTTIME_S, S_IRUGO,
+ [PTTIME] = __ATTR(PTTIME_S, 0444,
time_show, NULL),
- [PREST2] = __ATTR(PREST2_mS, S_IRUGO | S_IWUSR,
+ [PREST2] = __ATTR(PREST2_mS, 0644,
time_show, time_store),
- [PPULS2] = __ATTR(PPULS2_mS, S_IRUGO | S_IWUSR,
+ [PPULS2] = __ATTR(PPULS2_uC, 0644,
coulomb_show, coulomb_store),
- [NREST2] = __ATTR(NREST2_mS, S_IRUGO | S_IWUSR,
+ [NREST2] = __ATTR(NREST2_mS, 0644,
time_show, time_store),
- [NPULS2] = __ATTR(NPULS2_mS, S_IRUGO | S_IWUSR,
+ [NPULS2] = __ATTR(NPULS2_mS, 0644,
time_show, time_store),
- [VLIM2] = __ATTR(VLIM2_uV, S_IRUGO | S_IWUSR,
+ [VLIM2] = __ATTR(VLIM2_uV, 0644,
voltage_show, voltage_store),
- [PVOLT2] = __ATTR(PVOLT2_uV, S_IRUGO,
+ [PVOLT2] = __ATTR(PVOLT2_uV, 0444,
voltage_show, NULL),
- [RVOLT2] = __ATTR(RVOLT2_uV, S_IRUGO,
+ [RVOLT2] = __ATTR(RVOLT2_uV, 0444,
voltage_show, NULL),
- [PCUR2] = __ATTR(PCUR2_uA, S_IRUGO,
+ [PCUR2] = __ATTR(PCUR2_uA, 0444,
current_show, NULL),
- [SCNT] = __ATTR(SCNT, S_IRUGO | S_IWUSR,
+ [SCNT] = __ATTR(SCNT, 0644,
time_show, time_store),
- [VMAX] = __ATTR(VMAX_uV, S_IRUGO,
+ [VMAX] = __ATTR(VMAX_uV, 0444,
voltage_show, NULL),
- [SNUM] = __ATTR(SNUM, S_IRUGO | S_IWUSR,
- time_show, time_store),
- [VBATT] = __ATTR(VBATT_uV, S_IRUGO,
+ [SNUM] = __ATTR(SNUM, 0444,
+ time_show, NULL),
+ [VBATT] = __ATTR(VBATT_uV, 0444,
batt_prop_show, NULL),
- [IBATT] = __ATTR(IBATT_uA, S_IRUGO,
+ [IBATT] = __ATTR(IBATT_uA, 0444,
batt_prop_show, NULL),
- [BATTTEMP] = __ATTR(BATTTEMP_deciDegC, S_IRUGO,
+ [BATTTEMP] = __ATTR(BATTTEMP_deciDegC, 0444,
batt_prop_show, NULL),
- [BATTSOC] = __ATTR(BATTSOC, S_IRUGO,
+ [BATTSOC] = __ATTR(BATTSOC, 0444,
batt_prop_show, NULL),
__ATTR_NULL,
};
-static void get_chg_props(struct qnovo *chip, struct chg_props *cp)
+static int qnovo_update_status(struct qnovo *chip)
{
- union power_supply_propval pval;
u8 val = 0;
int rc;
+ bool charging;
+ bool changed = false;
- cp->charging = true;
- rc = qnovo_read(chip, QNOVO_ERROR_STS, &val, 1);
+ rc = qnovo_read(chip, QNOVO_ERROR_STS2, &val, 1);
if (rc < 0) {
pr_err("Couldn't read error sts rc = %d\n", rc);
- cp->charging = false;
+ charging = false;
} else {
- cp->charging = (!(val & QNOVO_ERROR_BIT));
+ charging = !(val & QNOVO_ERROR_CHARGING_DISABLED);
}
- if (chip->wa_flags & QNOVO_NO_ERR_STS_BIT) {
- /*
- * on v1.0 and v1.1 pmic's force charging to true
- * if things are not good to charge s/w gets a PTRAIN_DONE
- * interrupt
- */
- cp->charging = true;
- }
+ if (chip->ok_to_qnovo ^ charging) {
- cp->usb_online = false;
- if (!chip->usb_psy)
- chip->usb_psy = power_supply_get_by_name("usb");
- if (chip->usb_psy) {
- rc = power_supply_get_property(chip->usb_psy,
- POWER_SUPPLY_PROP_ONLINE, &pval);
- if (rc < 0)
- pr_err("Couldn't read usb online rc = %d\n", rc);
- else
- cp->usb_online = (bool)pval.intval;
- }
+ vote(chip->disable_votable, OK_TO_QNOVO_VOTER, !charging, 0);
+ if (!charging)
+ vote(chip->disable_votable, USER_VOTER, true, 0);
- cp->dc_online = false;
- if (!chip->dc_psy)
- chip->dc_psy = power_supply_get_by_name("dc");
- if (chip->dc_psy) {
- rc = power_supply_get_property(chip->dc_psy,
- POWER_SUPPLY_PROP_ONLINE, &pval);
- if (rc < 0)
- pr_err("Couldn't read dc online rc = %d\n", rc);
- else
- cp->dc_online = (bool)pval.intval;
+ chip->ok_to_qnovo = charging;
+ changed = true;
}
-}
-static void get_chg_status(struct qnovo *chip, const struct chg_props *cp,
- struct chg_status *cs)
-{
- cs->ok_to_qnovo = false;
-
- if (cp->charging &&
- (cp->usb_online || cp->dc_online))
- cs->ok_to_qnovo = true;
+ return changed;
}
static void status_change_work(struct work_struct *work)
{
struct qnovo *chip = container_of(work,
struct qnovo, status_change_work);
- bool notify_uevent = false;
- struct chg_props cp;
- struct chg_status cs;
-
- get_chg_props(chip, &cp);
- get_chg_status(chip, &cp, &cs);
-
- if (cs.ok_to_qnovo ^ chip->cs.ok_to_qnovo) {
- /*
- * when it is not okay to Qnovo charge, disable both voters,
- * so that when it becomes okay to Qnovo charge the user voter
- * has to specifically enable its vote to being Qnovo charging
- */
- if (!cs.ok_to_qnovo) {
- vote(chip->disable_votable, OK_TO_QNOVO_VOTER, 1, 0);
- vote(chip->disable_votable, USER_VOTER, 1, 0);
- } else {
- vote(chip->disable_votable, OK_TO_QNOVO_VOTER, 0, 0);
- }
- notify_uevent = true;
- }
- memcpy(&chip->cp, &cp, sizeof(struct chg_props));
- memcpy(&chip->cs, &cs, sizeof(struct chg_status));
-
- if (notify_uevent)
+ if (qnovo_update_status(chip))
kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE);
}
@@ -1186,8 +1148,8 @@ static int qnovo_notifier_call(struct notifier_block *nb,
if (ev != PSY_EVENT_PROP_CHANGED)
return NOTIFY_OK;
- if ((strcmp(psy->desc->name, "battery") == 0)
- || (strcmp(psy->desc->name, "usb") == 0))
+
+ if (strcmp(psy->desc->name, "battery") == 0)
schedule_work(&chip->status_change_work);
return NOTIFY_OK;
@@ -1197,8 +1159,7 @@ static irqreturn_t handle_ptrain_done(int irq, void *data)
{
struct qnovo *chip = data;
- /* disable user voter here */
- vote(chip->disable_votable, USER_VOTER, 0, 0);
+ qnovo_update_status(chip);
kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE);
return IRQ_HANDLED;
}
@@ -1211,7 +1172,14 @@ static int qnovo_hw_init(struct qnovo *chip)
u8 vadc_offset, vadc_gain;
u8 val;
- vote(chip->disable_votable, USER_VOTER, 1, 0);
+ vote(chip->disable_votable, USER_VOTER, true, 0);
+
+ val = 0;
+ rc = qnovo_write(chip, QNOVO_STRM_CTRL, &val, 1);
+ if (rc < 0) {
+ pr_err("Couldn't write iadc bitstream control rc = %d\n", rc);
+ return rc;
+ }
rc = qnovo_read(chip, QNOVO_IADC_OFFSET_0, &iadc_offset_external, 1);
if (rc < 0) {
@@ -1219,12 +1187,28 @@ static int qnovo_hw_init(struct qnovo *chip)
return rc;
}
+ /* stored as an 8 bit 2's complement signed integer */
+ val = -1 * iadc_offset_external;
+ rc = qnovo_write(chip, QNOVO_TR_IADC_OFFSET_0, &val, 1);
+ if (rc < 0) {
+ pr_err("Couldn't write iadc offset rc = %d\n", rc);
+ return rc;
+ }
+
rc = qnovo_read(chip, QNOVO_IADC_OFFSET_1, &iadc_offset_internal, 1);
if (rc < 0) {
pr_err("Couldn't read iadc internal offset rc = %d\n", rc);
return rc;
}
+ /* stored as an 8 bit 2's complement signed integer */
+ val = -1 * iadc_offset_internal;
+ rc = qnovo_write(chip, QNOVO_TR_IADC_OFFSET_1, &val, 1);
+ if (rc < 0) {
+ pr_err("Couldn't write iadc offset rc = %d\n", rc);
+ return rc;
+ }
+
rc = qnovo_read(chip, QNOVO_IADC_GAIN_0, &iadc_gain_external, 1);
if (rc < 0) {
pr_err("Couldn't read iadc external gain rc = %d\n", rc);
@@ -1249,53 +1233,20 @@ static int qnovo_hw_init(struct qnovo *chip)
return rc;
}
- chip->external_offset_nA = (s64)iadc_offset_external * IADC_LSB_NA;
- chip->internal_offset_nA = (s64)iadc_offset_internal * IADC_LSB_NA;
- chip->offset_nV = (s64)vadc_offset * VADC_LSB_NA;
+ chip->external_offset_nA = (s64)(s8)iadc_offset_external * IADC_LSB_NA;
+ chip->internal_offset_nA = (s64)(s8)iadc_offset_internal * IADC_LSB_NA;
+ chip->offset_nV = (s64)(s8)vadc_offset * VADC_LSB_NA;
chip->external_i_gain_mega
- = 1000000000 + (s64)iadc_gain_external * GAIN_LSB_FACTOR;
+ = 1000000000 + (s64)(s8)iadc_gain_external * GAIN_LSB_FACTOR;
chip->external_i_gain_mega
= div_s64(chip->external_i_gain_mega, 1000);
chip->internal_i_gain_mega
- = 1000000000 + (s64)iadc_gain_internal * GAIN_LSB_FACTOR;
+ = 1000000000 + (s64)(s8)iadc_gain_internal * GAIN_LSB_FACTOR;
chip->internal_i_gain_mega
= div_s64(chip->internal_i_gain_mega, 1000);
- chip->v_gain_mega = 1000000000 + (s64)vadc_gain * GAIN_LSB_FACTOR;
+ chip->v_gain_mega = 1000000000 + (s64)(s8)vadc_gain * GAIN_LSB_FACTOR;
chip->v_gain_mega = div_s64(chip->v_gain_mega, 1000);
- val = 0;
- rc = qnovo_write(chip, QNOVO_STRM_CTRL, &val, 1);
- if (rc < 0) {
- pr_err("Couldn't write iadc bitsteam control rc = %d\n", rc);
- return rc;
- }
-
- rc = qnovo_read(chip, QNOVO_TR_IADC_OFFSET_0, &val, 1);
- if (rc < 0) {
- pr_err("Couldn't read iadc offset rc = %d\n", rc);
- return rc;
- }
-
- val *= -1;
- rc = qnovo_write(chip, QNOVO_TR_IADC_OFFSET_0, &val, 1);
- if (rc < 0) {
- pr_err("Couldn't write iadc offset rc = %d\n", rc);
- return rc;
- }
-
- rc = qnovo_read(chip, QNOVO_TR_IADC_OFFSET_1, &val, 1);
- if (rc < 0) {
- pr_err("Couldn't read iadc offset rc = %d\n", rc);
- return rc;
- }
-
- val *= -1;
- rc = qnovo_write(chip, QNOVO_TR_IADC_OFFSET_1, &val, 1);
- if (rc < 0) {
- pr_err("Couldn't write iadc offset rc = %d\n", rc);
- return rc;
- }
-
return 0;
}
@@ -1333,6 +1284,9 @@ static int qnovo_request_interrupts(struct qnovo *chip)
irq_ptrain_done, rc);
return rc;
}
+
+ enable_irq_wake(irq_ptrain_done);
+
return rc;
}
@@ -1362,13 +1316,6 @@ static int qnovo_probe(struct platform_device *pdev)
return rc;
}
- rc = qnovo_check_chg_version(chip);
- if (rc < 0) {
- if (rc != -EPROBE_DEFER)
- pr_err("Couldn't check version rc=%d\n", rc);
- return rc;
- }
-
/* set driver data before resources request it */
platform_set_drvdata(pdev, chip);
@@ -1414,6 +1361,8 @@ static int qnovo_probe(struct platform_device *pdev)
goto unreg_notifier;
}
+ device_init_wakeup(chip->dev, true);
+
return rc;
unreg_notifier:
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 7311c56d9564..e8249163e948 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -838,7 +838,9 @@ static enum power_supply_property smb2_batt_props[] = {
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_VOLTAGE_QNOVO,
POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_QNOVO,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TECHNOLOGY,
@@ -910,6 +912,9 @@ static int smb2_batt_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
val->intval = get_client_vote(chg->fv_votable, DEFAULT_VOTER);
break;
+ case POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE:
+ rc = smblib_get_prop_charge_qnovo_enable(chg, val);
+ break;
case POWER_SUPPLY_PROP_VOLTAGE_QNOVO:
val->intval = chg->qnovo_fv_uv;
break;
@@ -985,12 +990,17 @@ static int smb2_batt_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
vote(chg->fv_votable, DEFAULT_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);
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);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
@@ -1534,13 +1544,6 @@ static int smb2_init_hw(struct smb2 *chip)
return rc;
}
- rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG,
- QNOVO_PT_ENABLE_CMD_BIT, QNOVO_PT_ENABLE_CMD_BIT);
- if (rc < 0) {
- dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc);
- return rc;
- }
-
/* configure step charging */
rc = smb2_config_step_charging(chip);
if (rc < 0) {
@@ -1653,6 +1656,15 @@ static int smb2_init_hw(struct smb2 *chip)
return rc;
}
+static int smb2_post_init(struct smb2 *chip)
+{
+ struct smb_charger *chg = &chip->chg;
+
+ rerun_election(chg->usb_irq_enable_votable);
+
+ return 0;
+}
+
static int smb2_chg_config_init(struct smb2 *chip)
{
struct smb_charger *chg = &chip->chg;
@@ -2182,6 +2194,8 @@ static int smb2_probe(struct platform_device *pdev)
goto cleanup;
}
+ smb2_post_init(chip);
+
smb2_create_debugfs(chip);
rc = smblib_get_prop_usb_present(chg, &val);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index bac48a62b6fd..51c87f963307 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -725,7 +725,6 @@ void smblib_suspend_on_debug_battery(struct smb_charger *chg)
int smblib_rerun_apsd_if_required(struct smb_charger *chg)
{
- const struct apsd_result *apsd_result;
union power_supply_propval val;
int rc;
@@ -738,12 +737,6 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg)
if (!val.intval)
return 0;
- apsd_result = smblib_get_apsd_result(chg);
- if ((apsd_result->pst != POWER_SUPPLY_TYPE_UNKNOWN)
- && (apsd_result->pst != POWER_SUPPLY_TYPE_USB))
- /* if type is not usb or unknown no need to rerun apsd */
- return 0;
-
/* fetch the DPDM regulator */
if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
"dpdm-supply", NULL)) {
@@ -1130,6 +1123,26 @@ static int smblib_hvdcp_hw_inov_dis_vote_callback(struct votable *votable,
return rc;
}
+static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
+ void *data, int enable, const char *client)
+{
+ struct smb_charger *chg = data;
+
+ if (!chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq ||
+ !chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq)
+ return 0;
+
+ if (enable) {
+ enable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
+ enable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
+ } else {
+ disable_irq(chg->irq_info[INPUT_CURRENT_LIMIT_IRQ].irq);
+ disable_irq(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq);
+ }
+
+ return 0;
+}
+
/*******************
* VCONN REGULATOR *
* *****************/
@@ -1326,6 +1339,14 @@ int smblib_vbus_regulator_enable(struct regulator_dev *rdev)
if (chg->otg_en)
goto unlock;
+ if (!chg->usb_icl_votable) {
+ chg->usb_icl_votable = find_votable("USB_ICL");
+
+ if (!chg->usb_icl_votable)
+ return -EINVAL;
+ }
+ vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, true, 0);
+
rc = _smblib_vbus_regulator_enable(rdev);
if (rc >= 0)
chg->otg_en = true;
@@ -1389,6 +1410,8 @@ int smblib_vbus_regulator_disable(struct regulator_dev *rdev)
if (rc >= 0)
chg->otg_en = false;
+ if (chg->usb_icl_votable)
+ vote(chg->usb_icl_votable, USBIN_USBIN_BOOST_VOTER, false, 0);
unlock:
mutex_unlock(&chg->otg_oc_lock);
return rc;
@@ -1702,6 +1725,23 @@ int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
return 0;
}
+int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg,
+ union power_supply_propval *val)
+{
+ int rc;
+ u8 stat;
+
+ rc = smblib_read(chg, QNOVO_PT_ENABLE_CMD_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read QNOVO_PT_ENABLE_CMD rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ val->intval = (bool)(stat & QNOVO_PT_ENABLE_CMD_BIT);
+ return 0;
+}
+
/***********************
* BATTERY PSY SETTERS *
***********************/
@@ -1766,6 +1806,22 @@ int smblib_set_prop_system_temp_level(struct smb_charger *chg,
return 0;
}
+int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
+ const union power_supply_propval *val)
+{
+ int rc = 0;
+
+ rc = smblib_masked_write(chg, QNOVO_PT_ENABLE_CMD_REG,
+ QNOVO_PT_ENABLE_CMD_BIT,
+ val->intval ? QNOVO_PT_ENABLE_CMD_BIT : 0);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't enable qnovo rc=%d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
int smblib_rerun_aicl(struct smb_charger *chg)
{
int rc, settled_icl_ua;
@@ -2424,6 +2480,22 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg,
return -EINVAL;
}
+ if (power_role == UFP_EN_CMD_BIT) {
+ /* disable PBS workaround when forcing sink mode */
+ rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
+ rc);
+ }
+ } else {
+ /* restore it back to 0xA5 */
+ rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't write to TM_IO_DTEST4_SEL rc=%d\n",
+ rc);
+ }
+ }
+
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
TYPEC_POWER_ROLE_CMD_MASK, power_role);
if (rc < 0) {
@@ -2491,6 +2563,7 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
vote(chg->apsd_disable_votable, PD_VOTER, pd_active, 0);
vote(chg->pd_allowed_votable, PD_VOTER, pd_active, 0);
+ vote(chg->usb_irq_enable_votable, PD_VOTER, pd_active, 0);
/*
* VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2 line
@@ -3325,6 +3398,10 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
/* could be a legacy cable, try doing hvdcp */
try_rerun_apsd_for_hvdcp(chg);
+ /* enable HDC and ICL irq for QC2/3 charger */
+ if (qc_charger)
+ vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
+
/*
* HVDCP detection timeout done
* If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
@@ -3575,6 +3652,8 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0);
+ vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
+ vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
/* reset votes from vbus_cc_short */
vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
@@ -4257,6 +4336,15 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
+ chg->usb_irq_enable_votable = create_votable("USB_IRQ_DISABLE",
+ VOTE_SET_ANY,
+ smblib_usb_irq_enable_vote_callback,
+ chg);
+ if (IS_ERR(chg->usb_irq_enable_votable)) {
+ rc = PTR_ERR(chg->usb_irq_enable_votable);
+ return rc;
+ }
+
return rc;
}
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index de236164e6b2..048e7c2b4091 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -32,10 +32,12 @@ enum print_reason {
#define USER_VOTER "USER_VOTER"
#define PD_VOTER "PD_VOTER"
#define DCP_VOTER "DCP_VOTER"
+#define QC_VOTER "QC_VOTER"
#define PL_USBIN_USBIN_VOTER "PL_USBIN_USBIN_VOTER"
#define USB_PSY_VOTER "USB_PSY_VOTER"
#define PL_TAPER_WORK_RUNNING_VOTER "PL_TAPER_WORK_RUNNING_VOTER"
#define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER"
+#define PL_QNOVO_VOTER "PL_QNOVO_VOTER"
#define USBIN_I_VOTER "USBIN_I_VOTER"
#define USBIN_V_VOTER "USBIN_V_VOTER"
#define CHG_STATE_VOTER "CHG_STATE_VOTER"
@@ -49,6 +51,7 @@ enum print_reason {
#define VBUS_CC_SHORT_VOTER "VBUS_CC_SHORT_VOTER"
#define PD_INACTIVE_VOTER "PD_INACTIVE_VOTER"
#define BOOST_BACK_VOTER "BOOST_BACK_VOTER"
+#define USBIN_USBIN_BOOST_VOTER "USBIN_USBIN_BOOST_VOTER"
#define HVDCP_INDIRECT_VOTER "HVDCP_INDIRECT_VOTER"
#define MICRO_USB_VOTER "MICRO_USB_VOTER"
#define DEBUG_BOARD_VOTER "DEBUG_BOARD_VOTER"
@@ -272,6 +275,7 @@ struct smb_charger {
struct votable *hvdcp_enable_votable;
struct votable *apsd_disable_votable;
struct votable *hvdcp_hw_inov_dis_votable;
+ struct votable *usb_irq_enable_votable;
/* work */
struct work_struct bms_update_work;
@@ -455,6 +459,8 @@ int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_die_health(struct smb_charger *chg,
union power_supply_propval *val);
+int smblib_get_prop_charge_qnovo_enable(struct smb_charger *chg,
+ union power_supply_propval *val);
int smblib_set_prop_pd_current_max(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_usb_current_max(struct smb_charger *chg,
@@ -475,6 +481,8 @@ int smblib_get_prop_slave_current_now(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_set_prop_ship_mode(struct smb_charger *chg,
const union power_supply_propval *val);
+int smblib_set_prop_charge_qnovo_enable(struct smb_charger *chg,
+ const union power_supply_propval *val);
void smblib_suspend_on_debug_battery(struct smb_charger *chg);
int smblib_rerun_apsd_if_required(struct smb_charger *chg);
int smblib_get_prop_fcc_delta(struct smb_charger *chg,
diff --git a/drivers/power/supply/qcom/smb-reg.h b/drivers/power/supply/qcom/smb-reg.h
index f7c13390d477..b79060094cf6 100644
--- a/drivers/power/supply/qcom/smb-reg.h
+++ b/drivers/power/supply/qcom/smb-reg.h
@@ -1019,6 +1019,8 @@ enum {
#define CFG_BUCKBOOST_FREQ_SELECT_BUCK_REG (MISC_BASE + 0xA0)
#define CFG_BUCKBOOST_FREQ_SELECT_BOOST_REG (MISC_BASE + 0xA1)
+#define TM_IO_DTEST4_SEL (MISC_BASE + 0xE9)
+
/* CHGR FREQ Peripheral registers */
#define FREQ_CLK_DIV_REG (CHGR_FREQ_BASE + 0x50)
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index d57944e18e3b..4916c87aced8 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -96,6 +96,7 @@ struct smb_dt_props {
int dc_icl_ua;
int chg_temp_max_mdegc;
int connector_temp_max_mdegc;
+ int pl_mode;
};
struct smb138x {
@@ -161,6 +162,11 @@ static int smb138x_parse_dt(struct smb138x *chip)
return -EINVAL;
}
+ rc = of_property_read_u32(node,
+ "qcom,parallel-mode", &chip->dt.pl_mode);
+ if (rc < 0)
+ chip->dt.pl_mode = POWER_SUPPLY_PL_USBMID_USBMID;
+
chip->dt.suspend_input = of_property_read_bool(node,
"qcom,suspend-input");
@@ -529,6 +535,8 @@ static enum power_supply_property smb138x_parallel_props[] = {
POWER_SUPPLY_PROP_CHARGING_ENABLED,
POWER_SUPPLY_PROP_PIN_ENABLED,
POWER_SUPPLY_PROP_INPUT_SUSPEND,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_NOW,
@@ -568,6 +576,19 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
rc = smblib_get_usb_suspend(chg, &val->intval);
break;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
+ if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ rc = smblib_get_prop_input_current_limited(chg, val);
+ else
+ val->intval = 0;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ rc = smblib_get_charge_param(chg, &chg->param.usb_icl,
+ &val->intval);
+ else
+ val->intval = 0;
+ break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
break;
@@ -588,7 +609,7 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
val->strval = "smb138x";
break;
case POWER_SUPPLY_PROP_PARALLEL_MODE:
- val->intval = POWER_SUPPLY_PL_USBMID_USBMID;
+ val->intval = chip->dt.pl_mode;
break;
case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
val->intval = smb138x_get_prop_connector_health(chip);
@@ -647,6 +668,11 @@ static int smb138x_parallel_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_INPUT_SUSPEND:
rc = smb138x_set_parallel_suspend(chip, (bool)val->intval);
break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN)
+ rc = smblib_set_charge_param(chg, &chg->param.usb_icl,
+ val->intval);
+ break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval);
break;
@@ -1458,6 +1484,15 @@ static int smb138x_slave_probe(struct smb138x *chip)
goto cleanup;
}
+ if (chip->dt.pl_mode == POWER_SUPPLY_PL_USBIN_USBIN) {
+ rc = smb138x_init_vbus_regulator(chip);
+ if (rc < 0) {
+ pr_err("Couldn't initialize vbus regulator rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
rc = smb138x_init_parallel_psy(chip);
if (rc < 0) {
pr_err("Couldn't initialize parallel psy rc=%d\n", rc);
@@ -1482,6 +1517,8 @@ 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;
}
diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 117fccf7934a..01a6a83f625d 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -65,7 +65,6 @@
#define PCA9685_MAXCHAN 0x10
#define LED_FULL (1 << 4)
-#define MODE1_RESTART (1 << 7)
#define MODE1_SLEEP (1 << 4)
#define MODE2_INVRT (1 << 4)
#define MODE2_OUTDRV (1 << 2)
@@ -117,16 +116,6 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
udelay(500);
pca->period_ns = period_ns;
-
- /*
- * If the duty cycle did not change, restart PWM with
- * the same duty cycle to period ratio and return.
- */
- if (duty_ns == pca->duty_ns) {
- regmap_update_bits(pca->regmap, PCA9685_MODE1,
- MODE1_RESTART, 0x1);
- return 0;
- }
} else {
dev_err(chip->dev,
"prescaler not set: period out of bounds!\n");
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 88a5c497d5ed..4f9de7fda612 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -4705,12 +4705,13 @@ static void regulator_summary_show_subtree(struct seq_file *s,
seq_puts(s, "\n");
list_for_each_entry(consumer, &rdev->consumer_list, list) {
- if (consumer->dev->class == &regulator_class)
+ if (consumer->dev && consumer->dev->class == &regulator_class)
continue;
seq_printf(s, "%*s%-*s ",
(level + 1) * 3 + 1, "",
- 30 - (level + 1) * 3, dev_name(consumer->dev));
+ 30 - (level + 1) * 3,
+ consumer->dev ? dev_name(consumer->dev) : "deviceless");
switch (rdev->desc->type) {
case REGULATOR_VOLTAGE:
diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c
index aef28dbeb931..724e8a4c00da 100644
--- a/drivers/regulator/qpnp-lcdb-regulator.c
+++ b/drivers/regulator/qpnp-lcdb-regulator.c
@@ -24,6 +24,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
+#include <linux/qpnp/qpnp-revid.h>
#define QPNP_LCDB_REGULATOR_DRIVER_NAME "qcom,qpnp-lcdb-regulator"
@@ -192,6 +193,7 @@ struct qpnp_lcdb {
struct device *dev;
struct platform_device *pdev;
struct regmap *regmap;
+ struct pmic_revid_data *pmic_rev_id;
u32 base;
int sc_irq;
@@ -199,9 +201,6 @@ struct qpnp_lcdb {
bool ttw_enable;
bool ttw_mode_sw;
- /* top level DT params */
- bool force_module_reenable;
-
/* status parameters */
bool lcdb_enabled;
bool settings_saved;
@@ -579,6 +578,65 @@ static int qpnp_lcdb_ttw_exit(struct qpnp_lcdb *lcdb)
return 0;
}
+static int qpnp_lcdb_enable_wa(struct qpnp_lcdb *lcdb)
+{
+ int rc;
+ u8 val = 0;
+
+ /* required only for PM660L */
+ if (lcdb->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE)
+ return 0;
+
+ val = MODULE_EN_BIT;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
+ &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to enable lcdb rc= %d\n", rc);
+ return rc;
+ }
+
+ val = 0;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
+ &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to disable lcdb rc= %d\n", rc);
+ return rc;
+ }
+
+ /* execute the below for rev1.1 */
+ if (lcdb->pmic_rev_id->rev3 == PM660L_V1P1_REV3 &&
+ lcdb->pmic_rev_id->rev4 == PM660L_V1P1_REV4) {
+ /*
+ * delay to make sure that the MID pin – ie the
+ * output of the LCDB boost – returns to 0V
+ * after the module is disabled
+ */
+ usleep_range(10000, 10100);
+
+ rc = qpnp_lcdb_masked_write(lcdb,
+ lcdb->base + LCDB_MISC_CTL_REG,
+ DIS_SCP_BIT, DIS_SCP_BIT);
+ if (rc < 0) {
+ pr_err("Failed to disable SC rc=%d\n", rc);
+ return rc;
+ }
+ /* delay for SC-disable to take effect */
+ usleep_range(1000, 1100);
+
+ rc = qpnp_lcdb_masked_write(lcdb,
+ lcdb->base + LCDB_MISC_CTL_REG,
+ DIS_SCP_BIT, 0);
+ if (rc < 0) {
+ pr_err("Failed to enable SC rc=%d\n", rc);
+ return rc;
+ }
+ /* delay for SC-enable to take effect */
+ usleep_range(1000, 1100);
+ }
+
+ return 0;
+}
+
static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb)
{
int rc = 0, timeout, delay;
@@ -598,31 +656,20 @@ static int qpnp_lcdb_enable(struct qpnp_lcdb *lcdb)
}
}
+ rc = qpnp_lcdb_enable_wa(lcdb);
+ if (rc < 0) {
+ pr_err("Failed to execute enable_wa rc=%d\n", rc);
+ return rc;
+ }
+
val = MODULE_EN_BIT;
rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
&val, 1);
if (rc < 0) {
- pr_err("Failed to enable lcdb rc= %d\n", rc);
+ pr_err("Failed to disable lcdb rc= %d\n", rc);
goto fail_enable;
}
- if (lcdb->force_module_reenable) {
- val = 0;
- rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
- &val, 1);
- if (rc < 0) {
- pr_err("Failed to enable lcdb rc= %d\n", rc);
- goto fail_enable;
- }
- val = MODULE_EN_BIT;
- rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
- &val, 1);
- if (rc < 0) {
- pr_err("Failed to disable lcdb rc= %d\n", rc);
- goto fail_enable;
- }
- }
-
/* poll for vreg_ok */
timeout = 10;
delay = lcdb->bst.soft_start_us + lcdb->ldo.soft_start_us +
@@ -1674,7 +1721,8 @@ static int qpnp_lcdb_hw_init(struct qpnp_lcdb *lcdb)
return rc;
}
- if (lcdb->sc_irq >= 0) {
+ if (lcdb->sc_irq >= 0 &&
+ lcdb->pmic_rev_id->pmic_subtype != PM660L_SUBTYPE) {
lcdb->sc_count = 0;
rc = devm_request_threaded_irq(lcdb->dev, lcdb->sc_irq,
NULL, qpnp_lcdb_sc_irq_handler, IRQF_ONESHOT,
@@ -1714,7 +1762,23 @@ static int qpnp_lcdb_parse_dt(struct qpnp_lcdb *lcdb)
{
int rc = 0;
const char *label;
- struct device_node *temp, *node = lcdb->dev->of_node;
+ struct device_node *revid_dev_node, *temp, *node = lcdb->dev->of_node;
+
+ revid_dev_node = of_parse_phandle(node, "qcom,pmic-revid", 0);
+ if (!revid_dev_node) {
+ pr_err("Missing qcom,pmic-revid property - fail driver\n");
+ return -EINVAL;
+ }
+
+ lcdb->pmic_rev_id = get_revid_data(revid_dev_node);
+ if (IS_ERR(lcdb->pmic_rev_id)) {
+ pr_debug("Unable to get revid data\n");
+ /*
+ * revid should to be defined, return -EPROBE_DEFER
+ * until the revid module registers.
+ */
+ return -EPROBE_DEFER;
+ }
for_each_available_child_of_node(node, temp) {
rc = of_property_read_string(temp, "label", &label);
@@ -1742,9 +1806,6 @@ static int qpnp_lcdb_parse_dt(struct qpnp_lcdb *lcdb)
}
}
- lcdb->force_module_reenable = of_property_read_bool(node,
- "qcom,force-module-reenable");
-
if (of_property_read_bool(node, "qcom,ttw-enable")) {
rc = qpnp_lcdb_parse_ttw(lcdb);
if (rc < 0) {
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 5836751b8203..9bb934ed2a7a 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -748,9 +748,23 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
*/
static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
{
+ struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
+ struct rtc_time tm;
+ ktime_t now;
+
timer->enabled = 1;
+ __rtc_read_time(rtc, &tm);
+ now = rtc_tm_to_ktime(tm);
+
+ /* Skip over expired timers */
+ while (next) {
+ if (next->expires.tv64 >= now.tv64)
+ break;
+ next = timerqueue_iterate_next(next);
+ }
+
timerqueue_add(&rtc->timerqueue, &timer->node);
- if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) {
+ if (!next) {
struct rtc_wkalrm alarm;
int err;
alarm.time = rtc_ktime_to_tm(timer->node.expires);
diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
index c169a2cd4727..e29cc9fca0bf 100644
--- a/drivers/rtc/rtc-sun6i.c
+++ b/drivers/rtc/rtc-sun6i.c
@@ -37,9 +37,11 @@
/* Control register */
#define SUN6I_LOSC_CTRL 0x0000
+#define SUN6I_LOSC_CTRL_KEY (0x16aa << 16)
#define SUN6I_LOSC_CTRL_ALM_DHMS_ACC BIT(9)
#define SUN6I_LOSC_CTRL_RTC_HMS_ACC BIT(8)
#define SUN6I_LOSC_CTRL_RTC_YMD_ACC BIT(7)
+#define SUN6I_LOSC_CTRL_EXT_OSC BIT(0)
#define SUN6I_LOSC_CTRL_ACC_MASK GENMASK(9, 7)
/* RTC */
@@ -114,13 +116,17 @@ struct sun6i_rtc_dev {
void __iomem *base;
int irq;
unsigned long alarm;
+
+ spinlock_t lock;
};
static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
{
struct sun6i_rtc_dev *chip = (struct sun6i_rtc_dev *) id;
+ irqreturn_t ret = IRQ_NONE;
u32 val;
+ spin_lock(&chip->lock);
val = readl(chip->base + SUN6I_ALRM_IRQ_STA);
if (val & SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND) {
@@ -129,10 +135,11 @@ static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF);
- return IRQ_HANDLED;
+ ret = IRQ_HANDLED;
}
+ spin_unlock(&chip->lock);
- return IRQ_NONE;
+ return ret;
}
static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
@@ -140,6 +147,7 @@ static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
u32 alrm_val = 0;
u32 alrm_irq_val = 0;
u32 alrm_wake_val = 0;
+ unsigned long flags;
if (to) {
alrm_val = SUN6I_ALRM_EN_CNT_EN;
@@ -150,9 +158,11 @@ static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
chip->base + SUN6I_ALRM_IRQ_STA);
}
+ spin_lock_irqsave(&chip->lock, flags);
writel(alrm_val, chip->base + SUN6I_ALRM_EN);
writel(alrm_irq_val, chip->base + SUN6I_ALRM_IRQ_EN);
writel(alrm_wake_val, chip->base + SUN6I_ALARM_CONFIG);
+ spin_unlock_irqrestore(&chip->lock, flags);
}
static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
@@ -191,11 +201,15 @@ static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
static int sun6i_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
{
struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
+ unsigned long flags;
u32 alrm_st;
u32 alrm_en;
+ spin_lock_irqsave(&chip->lock, flags);
alrm_en = readl(chip->base + SUN6I_ALRM_IRQ_EN);
alrm_st = readl(chip->base + SUN6I_ALRM_IRQ_STA);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
wkalrm->enabled = !!(alrm_en & SUN6I_ALRM_EN_CNT_EN);
wkalrm->pending = !!(alrm_st & SUN6I_ALRM_EN_CNT_EN);
rtc_time_to_tm(chip->alarm, &wkalrm->time);
@@ -356,6 +370,7 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
+ spin_lock_init(&chip->lock);
platform_set_drvdata(pdev, chip);
chip->dev = &pdev->dev;
@@ -404,6 +419,10 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
/* disable alarm wakeup */
writel(0, chip->base + SUN6I_ALARM_CONFIG);
+ /* switch to the external, more precise, oscillator */
+ writel(SUN6I_LOSC_CTRL_KEY | SUN6I_LOSC_CTRL_EXT_OSC,
+ chip->base + SUN6I_LOSC_CTRL);
+
chip->rtc = rtc_device_register("rtc-sun6i", &pdev->dev,
&sun6i_rtc_ops, THIS_MODULE);
if (IS_ERR(chip->rtc)) {
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 94a8f4ab57bc..ae1dc37e4068 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -892,7 +892,7 @@ dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
dev_info = bdev->bd_disk->private_data;
if (!dev_info)
return -ENODEV;
- dev_sz = dev_info->end - dev_info->start;
+ dev_sz = dev_info->end - dev_info->start + 1;
offset = secnum * 512;
addr = (void *) (dev_info->start + offset);
*pfn = virt_to_phys(addr) >> PAGE_SHIFT;
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c
index 5d06253c2a7a..30e9fbbff051 100644
--- a/drivers/s390/cio/qdio_thinint.c
+++ b/drivers/s390/cio/qdio_thinint.c
@@ -147,11 +147,11 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq)
struct qdio_q *q;
int i;
- for_each_input_queue(irq, q, i) {
- if (!references_shared_dsci(irq) &&
- has_multiple_inq_on_dsci(irq))
- xchg(q->irq_ptr->dsci, 0);
+ if (!references_shared_dsci(irq) &&
+ has_multiple_inq_on_dsci(irq))
+ xchg(irq->dsci, 0);
+ for_each_input_queue(irq, q, i) {
if (q->u.in.queue_start_poll) {
/* skip if polling is enabled or already in work */
if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED,
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index bc0203f3d243..e415e1c58eb5 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -413,16 +413,23 @@ static int aac_src_check_health(struct aac_dev *dev)
u32 status = src_readl(dev, MUnit.OMR);
/*
+ * Check to see if the board panic'd.
+ */
+ if (unlikely(status & KERNEL_PANIC))
+ goto err_blink;
+
+ /*
* Check to see if the board failed any self tests.
*/
if (unlikely(status & SELF_TEST_FAILED))
- return -1;
+ goto err_out;
/*
- * Check to see if the board panic'd.
+ * Check to see if the board failed any self tests.
*/
- if (unlikely(status & KERNEL_PANIC))
- return (status >> 16) & 0xFF;
+ if (unlikely(status & MONITOR_PANIC))
+ goto err_out;
+
/*
* Wait for the adapter to be up and running.
*/
@@ -432,6 +439,12 @@ static int aac_src_check_health(struct aac_dev *dev)
* Everything is OK
*/
return 0;
+
+err_out:
+ return -1;
+
+err_blink:
+ return (status > 16) & 0xFF;
}
/**
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 33ec4fa39ccb..f224cdb2fce4 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -1182,6 +1182,7 @@ struct lpfc_mbx_wq_create {
#define lpfc_mbx_wq_create_page_size_SHIFT 0
#define lpfc_mbx_wq_create_page_size_MASK 0x000000FF
#define lpfc_mbx_wq_create_page_size_WORD word1
+#define LPFC_WQ_PAGE_SIZE_4096 0x1
#define lpfc_mbx_wq_create_wqe_size_SHIFT 8
#define lpfc_mbx_wq_create_wqe_size_MASK 0x0000000F
#define lpfc_mbx_wq_create_wqe_size_WORD word1
@@ -1253,6 +1254,7 @@ struct rq_context {
#define lpfc_rq_context_page_size_SHIFT 0 /* Version 1 Only */
#define lpfc_rq_context_page_size_MASK 0x000000FF
#define lpfc_rq_context_page_size_WORD word0
+#define LPFC_RQ_PAGE_SIZE_4096 0x1
uint32_t reserved1;
uint32_t word2;
#define lpfc_rq_context_cq_id_SHIFT 16
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 92dfd6a5178c..f5aeda8f014f 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -13475,7 +13475,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
LPFC_WQ_WQE_SIZE_128);
bf_set(lpfc_mbx_wq_create_page_size,
&wq_create->u.request_1,
- (PAGE_SIZE/SLI4_PAGE_SIZE));
+ LPFC_WQ_PAGE_SIZE_4096);
page = wq_create->u.request_1.page;
break;
}
@@ -13501,8 +13501,9 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
LPFC_WQ_WQE_SIZE_128);
break;
}
- bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1,
- (PAGE_SIZE/SLI4_PAGE_SIZE));
+ bf_set(lpfc_mbx_wq_create_page_size,
+ &wq_create->u.request_1,
+ LPFC_WQ_PAGE_SIZE_4096);
page = wq_create->u.request_1.page;
break;
default:
@@ -13688,7 +13689,7 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq,
LPFC_RQE_SIZE_8);
bf_set(lpfc_rq_context_page_size,
&rq_create->u.request.context,
- (PAGE_SIZE/SLI4_PAGE_SIZE));
+ LPFC_RQ_PAGE_SIZE_4096);
} else {
switch (hrq->entry_count) {
default:
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index 9c780740fb82..e712fe745955 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -737,8 +737,8 @@ static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf
mv_dprintk("device %016llx not ready.\n",
SAS_ADDR(dev->sas_addr));
- rc = SAS_PHY_DOWN;
- return rc;
+ rc = SAS_PHY_DOWN;
+ return rc;
}
tei.port = dev->port->lldd_port;
if (tei.port && !tei.port->port_attached && !tmf) {
diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c
index e7649ed3f667..4d655b568269 100644
--- a/drivers/scsi/scsi_dh.c
+++ b/drivers/scsi/scsi_dh.c
@@ -289,20 +289,6 @@ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
}
EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
-static struct scsi_device *get_sdev_from_queue(struct request_queue *q)
-{
- struct scsi_device *sdev;
- unsigned long flags;
-
- spin_lock_irqsave(q->queue_lock, flags);
- sdev = q->queuedata;
- if (!sdev || !get_device(&sdev->sdev_gendev))
- sdev = NULL;
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- return sdev;
-}
-
/*
* scsi_dh_activate - activate the path associated with the scsi_device
* corresponding to the given request queue.
@@ -321,7 +307,7 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data)
struct scsi_device *sdev;
int err = SCSI_DH_NOSYS;
- sdev = get_sdev_from_queue(q);
+ sdev = scsi_device_from_queue(q);
if (!sdev) {
if (fn)
fn(data, err);
@@ -368,7 +354,7 @@ int scsi_dh_set_params(struct request_queue *q, const char *params)
struct scsi_device *sdev;
int err = -SCSI_DH_NOSYS;
- sdev = get_sdev_from_queue(q);
+ sdev = scsi_device_from_queue(q);
if (!sdev)
return err;
@@ -391,7 +377,7 @@ int scsi_dh_attach(struct request_queue *q, const char *name)
struct scsi_device_handler *scsi_dh;
int err = 0;
- sdev = get_sdev_from_queue(q);
+ sdev = scsi_device_from_queue(q);
if (!sdev)
return -ENODEV;
@@ -429,7 +415,7 @@ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp)
struct scsi_device *sdev;
const char *handler_name = NULL;
- sdev = get_sdev_from_queue(q);
+ sdev = scsi_device_from_queue(q);
if (!sdev)
return NULL;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index cf5b99e1f12b..887045ae5d10 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1120,7 +1120,8 @@ int scsi_init_io(struct scsi_cmnd *cmd)
bool is_mq = (rq->mq_ctx != NULL);
int error;
- BUG_ON(!rq->nr_phys_segments);
+ if (WARN_ON_ONCE(!rq->nr_phys_segments))
+ return -EINVAL;
error = scsi_init_sgtable(rq, &cmd->sdb);
if (error)
@@ -2214,6 +2215,29 @@ void scsi_mq_destroy_tags(struct Scsi_Host *shost)
blk_mq_free_tag_set(&shost->tag_set);
}
+/**
+ * scsi_device_from_queue - return sdev associated with a request_queue
+ * @q: The request queue to return the sdev from
+ *
+ * Return the sdev associated with a request queue or NULL if the
+ * request_queue does not reference a SCSI device.
+ */
+struct scsi_device *scsi_device_from_queue(struct request_queue *q)
+{
+ struct scsi_device *sdev = NULL;
+
+ if (q->mq_ops) {
+ if (q->mq_ops == &scsi_mq_ops)
+ sdev = q->queuedata;
+ } else if (q->request_fn == scsi_request_fn)
+ sdev = q->queuedata;
+ if (!sdev || !get_device(&sdev->sdev_gendev))
+ sdev = NULL;
+
+ return sdev;
+}
+EXPORT_SYMBOL_GPL(scsi_device_from_queue);
+
/*
* Function: scsi_block_requests()
*
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index e52090b18327..93a523b42d3d 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1760,6 +1760,10 @@ sg_start_req(Sg_request *srp, unsigned char *cmd)
return res;
iov_iter_truncate(&i, hp->dxfer_len);
+ if (!iov_iter_count(&i)) {
+ kfree(iov);
+ return -EINVAL;
+ }
res = blk_rq_map_user_iov(q, rq, md, &i, GFP_ATOMIC);
kfree(iov);
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 0f636cc4c809..cd5c1c060481 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -135,6 +135,8 @@ struct hv_fc_wwn_packet {
#define SRB_FLAGS_PORT_DRIVER_RESERVED 0x0F000000
#define SRB_FLAGS_CLASS_DRIVER_RESERVED 0xF0000000
+#define SP_UNTAGGED ((unsigned char) ~0)
+#define SRB_SIMPLE_TAG_REQUEST 0x20
/*
* Platform neutral description of a scsi request -
@@ -354,6 +356,7 @@ enum storvsc_request_type {
#define SRB_STATUS_SUCCESS 0x01
#define SRB_STATUS_ABORTED 0x02
#define SRB_STATUS_ERROR 0x04
+#define SRB_STATUS_DATA_OVERRUN 0x12
#define SRB_STATUS(status) \
(status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN))
@@ -864,6 +867,13 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
switch (SRB_STATUS(vm_srb->srb_status)) {
case SRB_STATUS_ERROR:
/*
+ * Let upper layer deal with error when
+ * sense message is present.
+ */
+
+ if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID)
+ break;
+ /*
* If there is an error; offline the device since all
* error recovery strategies would have already been
* deployed on the host side. However, if the command
@@ -927,6 +937,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
struct scsi_sense_hdr sense_hdr;
struct vmscsi_request *vm_srb;
+ u32 data_transfer_length;
struct Scsi_Host *host;
struct storvsc_device *stor_dev;
struct hv_device *dev = host_dev->dev;
@@ -937,6 +948,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
host = stor_dev->host;
vm_srb = &cmd_request->vstor_packet.vm_srb;
+ data_transfer_length = vm_srb->data_transfer_length;
scmnd->result = vm_srb->scsi_status;
@@ -947,13 +959,20 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
&sense_hdr);
}
- if (vm_srb->srb_status != SRB_STATUS_SUCCESS)
+ if (vm_srb->srb_status != SRB_STATUS_SUCCESS) {
storvsc_handle_error(vm_srb, scmnd, host, sense_hdr.asc,
sense_hdr.ascq);
+ /*
+ * The Windows driver set data_transfer_length on
+ * SRB_STATUS_DATA_OVERRUN. On other errors, this value
+ * is untouched. In these cases we set it to 0.
+ */
+ if (vm_srb->srb_status != SRB_STATUS_DATA_OVERRUN)
+ data_transfer_length = 0;
+ }
scsi_set_resid(scmnd,
- cmd_request->payload->range.len -
- vm_srb->data_transfer_length);
+ cmd_request->payload->range.len - data_transfer_length);
scmnd->scsi_done(scmnd);
@@ -1409,6 +1428,13 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
vm_srb->win8_extension.srb_flags |=
SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
+ if (scmnd->device->tagged_supported) {
+ vm_srb->win8_extension.srb_flags |=
+ (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE);
+ vm_srb->win8_extension.queue_tag = SP_UNTAGGED;
+ vm_srb->win8_extension.queue_action = SRB_SIMPLE_TAG_REQUEST;
+ }
+
/* Build the SRB */
switch (scmnd->sc_data_direction) {
case DMA_TO_DEVICE:
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c891fc8d34a3..16f130dd3c76 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1388,7 +1388,7 @@ static void ufshcd_gate_work(struct work_struct *work)
* state to CLKS_ON.
*/
if (hba->clk_gating.is_suspended ||
- (hba->clk_gating.state == REQ_CLKS_ON)) {
+ (hba->clk_gating.state != REQ_CLKS_OFF)) {
hba->clk_gating.state = CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
diff --git a/drivers/soc/qcom/glink_private.h b/drivers/soc/qcom/glink_private.h
index cdd6988418f7..24053c853a83 100644
--- a/drivers/soc/qcom/glink_private.h
+++ b/drivers/soc/qcom/glink_private.h
@@ -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
@@ -693,6 +693,7 @@ enum ssr_command {
* edge: The G-Link edge name for the channel associated with
* this callback data
* do_cleanup_data: Structure containing the G-Link SSR do_cleanup message.
+ * cb_kref: Kref object to maintain cb_data reference.
*/
struct ssr_notify_data {
bool tx_done;
@@ -700,6 +701,7 @@ struct ssr_notify_data {
bool responded;
const char *edge;
struct do_cleanup_msg *do_cleanup_data;
+ struct kref cb_kref;
};
/**
@@ -734,6 +736,7 @@ struct subsys_info {
int notify_list_len;
bool link_up;
spinlock_t link_up_lock;
+ spinlock_t cb_lock;
};
/**
diff --git a/drivers/soc/qcom/glink_ssr.c b/drivers/soc/qcom/glink_ssr.c
index 5e2dbc8b1d20..7e23b0bc3852 100644
--- a/drivers/soc/qcom/glink_ssr.c
+++ b/drivers/soc/qcom/glink_ssr.c
@@ -115,6 +115,44 @@ static LIST_HEAD(subsystem_list);
static atomic_t responses_remaining = ATOMIC_INIT(0);
static wait_queue_head_t waitqueue;
+/**
+ * cb_data_release() - Free cb_data and set to NULL
+ * @kref_ptr: pointer to kref.
+ *
+ * This function releses cb_data.
+ */
+static inline void cb_data_release(struct kref *kref_ptr)
+{
+ struct ssr_notify_data *cb_data;
+
+ cb_data = container_of(kref_ptr, struct ssr_notify_data, cb_kref);
+ kfree(cb_data);
+}
+
+/**
+ * check_and_get_cb_data() - Try to get reference to kref of cb_data
+ * @ss_info: pointer to subsystem info structure.
+ *
+ * Return: NULL is cb_data is NULL, pointer to cb_data otherwise
+ */
+static struct ssr_notify_data *check_and_get_cb_data(
+ struct subsys_info *ss_info)
+{
+ struct ssr_notify_data *cb_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ss_info->cb_lock, flags);
+ if (ss_info->cb_data == NULL) {
+ GLINK_SSR_LOG("<SSR> %s: cb_data is NULL\n", __func__);
+ spin_unlock_irqrestore(&ss_info->cb_lock, flags);
+ return 0;
+ }
+ kref_get(&ss_info->cb_data->cb_kref);
+ cb_data = ss_info->cb_data;
+ spin_unlock_irqrestore(&ss_info->cb_lock, flags);
+ return cb_data;
+}
+
static void rx_done_cb_worker(struct work_struct *work)
{
struct rx_done_ch_work *rx_done_work =
@@ -338,8 +376,10 @@ void close_ch_worker(struct work_struct *work)
ss_info->link_state_handle = link_state_handle;
BUG_ON(!ss_info->cb_data);
- kfree(ss_info->cb_data);
+ spin_lock_irqsave(&ss_info->cb_lock, flags);
+ kref_put(&ss_info->cb_data->cb_kref, cb_data_release);
ss_info->cb_data = NULL;
+ spin_unlock_irqrestore(&ss_info->cb_lock, flags);
kfree(close_work);
}
@@ -507,13 +547,18 @@ int notify_for_subsystem(struct subsys_info *ss_info)
return -ENODEV;
}
handle = ss_info_channel->handle;
- ss_leaf_entry->cb_data = ss_info_channel->cb_data;
+ ss_leaf_entry->cb_data = check_and_get_cb_data(
+ ss_info_channel);
+ if (!ss_leaf_entry->cb_data) {
+ GLINK_SSR_LOG("<SSR> %s: CB data is NULL\n", __func__);
+ atomic_dec(&responses_remaining);
+ continue;
+ }
spin_lock_irqsave(&ss_info->link_up_lock, flags);
if (IS_ERR_OR_NULL(ss_info_channel->handle) ||
- !ss_info_channel->cb_data ||
!ss_info_channel->link_up ||
- ss_info_channel->cb_data->event
+ ss_leaf_entry->cb_data->event
!= GLINK_CONNECTED) {
GLINK_SSR_LOG(
@@ -526,6 +571,8 @@ int notify_for_subsystem(struct subsys_info *ss_info)
spin_unlock_irqrestore(&ss_info->link_up_lock, flags);
atomic_dec(&responses_remaining);
+ kref_put(&ss_leaf_entry->cb_data->cb_kref,
+ cb_data_release);
continue;
}
spin_unlock_irqrestore(&ss_info->link_up_lock, flags);
@@ -536,6 +583,8 @@ int notify_for_subsystem(struct subsys_info *ss_info)
GLINK_SSR_ERR(
"%s %s: Could not allocate do_cleanup_msg\n",
"<SSR>", __func__);
+ kref_put(&ss_leaf_entry->cb_data->cb_kref,
+ cb_data_release);
return -ENOMEM;
}
@@ -567,6 +616,8 @@ int notify_for_subsystem(struct subsys_info *ss_info)
__func__);
}
atomic_dec(&responses_remaining);
+ kref_put(&ss_leaf_entry->cb_data->cb_kref,
+ cb_data_release);
continue;
}
@@ -596,10 +647,12 @@ int notify_for_subsystem(struct subsys_info *ss_info)
__func__);
}
atomic_dec(&responses_remaining);
+ kref_put(&ss_leaf_entry->cb_data->cb_kref,
+ cb_data_release);
continue;
}
-
sequence_number++;
+ kref_put(&ss_leaf_entry->cb_data->cb_kref, cb_data_release);
}
wait_ret = wait_event_timeout(waitqueue,
@@ -608,6 +661,21 @@ int notify_for_subsystem(struct subsys_info *ss_info)
list_for_each_entry(ss_leaf_entry, &ss_info->notify_list,
notify_list_node) {
+ ss_info_channel =
+ get_info_for_subsystem(ss_leaf_entry->ssr_name);
+ if (ss_info_channel == NULL) {
+ GLINK_SSR_ERR(
+ "<SSR> %s: unable to find subsystem name\n",
+ __func__);
+ continue;
+ }
+
+ ss_leaf_entry->cb_data = check_and_get_cb_data(
+ ss_info_channel);
+ if (!ss_leaf_entry->cb_data) {
+ GLINK_SSR_LOG("<SSR> %s: CB data is NULL\n", __func__);
+ continue;
+ }
if (!wait_ret && !IS_ERR_OR_NULL(ss_leaf_entry->cb_data)
&& !ss_leaf_entry->cb_data->responded) {
GLINK_SSR_ERR("%s %s: Subsystem %s %s\n",
@@ -626,6 +694,7 @@ int notify_for_subsystem(struct subsys_info *ss_info)
if (!IS_ERR_OR_NULL(ss_leaf_entry->cb_data))
ss_leaf_entry->cb_data->responded = false;
+ kref_put(&ss_leaf_entry->cb_data->cb_kref, cb_data_release);
}
complete(&notifications_successful_complete);
return 0;
@@ -644,6 +713,7 @@ static int configure_and_open_channel(struct subsys_info *ss_info)
struct glink_open_config open_cfg;
struct ssr_notify_data *cb_data = NULL;
void *handle = NULL;
+ unsigned long flags;
if (!ss_info) {
GLINK_SSR_ERR("<SSR> %s: ss_info structure invalid\n",
@@ -660,7 +730,10 @@ static int configure_and_open_channel(struct subsys_info *ss_info)
cb_data->responded = false;
cb_data->event = GLINK_SSR_EVENT_INIT;
cb_data->edge = ss_info->edge;
+ spin_lock_irqsave(&ss_info->cb_lock, flags);
ss_info->cb_data = cb_data;
+ kref_init(&cb_data->cb_kref);
+ spin_unlock_irqrestore(&ss_info->cb_lock, flags);
memset(&open_cfg, 0, sizeof(struct glink_open_config));
@@ -876,6 +949,7 @@ static int glink_ssr_probe(struct platform_device *pdev)
ss_info->link_state_handle = NULL;
ss_info->cb_data = NULL;
spin_lock_init(&ss_info->link_up_lock);
+ spin_lock_init(&ss_info->cb_lock);
nb = kmalloc(sizeof(struct restart_notifier_block), GFP_KERNEL);
if (!nb) {
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 16ab2400cd69..0b35caa86d51 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -48,6 +48,11 @@
#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
@@ -62,7 +67,7 @@ module_param(qmi_timeout, ulong, 0600);
#define WLFW_CLIENT_ID 0x4b4e454c
#define MAX_PROP_SIZE 32
#define NUM_LOG_PAGES 10
-#define NUM_REG_LOG_PAGES 4
+#define NUM_LOG_LONG_PAGES 4
#define ICNSS_MAGIC 0x5abc5abc
#define ICNSS_SERVICE_LOCATION_CLIENT_NAME "ICNSS-WLAN"
@@ -77,6 +82,11 @@ module_param(qmi_timeout, ulong, 0600);
ipc_log_string(icnss_ipc_log_context, _x); \
} while (0)
+#define icnss_ipc_log_long_string(_x...) do { \
+ if (icnss_ipc_log_long_context) \
+ ipc_log_string(icnss_ipc_log_long_context, _x); \
+ } while (0)
+
#define icnss_pr_err(_fmt, ...) do { \
pr_err(_fmt, ##__VA_ARGS__); \
icnss_ipc_log_string("ERR: " pr_fmt(_fmt), \
@@ -101,6 +111,12 @@ module_param(qmi_timeout, ulong, 0600);
##__VA_ARGS__); \
} while (0)
+#define icnss_pr_vdbg(_fmt, ...) do { \
+ pr_debug(_fmt, ##__VA_ARGS__); \
+ icnss_ipc_log_long_string("DBG: " pr_fmt(_fmt), \
+ ##__VA_ARGS__); \
+ } while (0)
+
#ifdef CONFIG_ICNSS_DEBUG
#define ICNSS_ASSERT(_condition) do { \
if (!(_condition)) { \
@@ -138,6 +154,7 @@ uint64_t dynamic_feature_mask = QMI_WLFW_FW_REJUVENATE_V01;
module_param(dynamic_feature_mask, ullong, 0600);
void *icnss_ipc_log_context;
+void *icnss_ipc_log_long_context;
#define ICNSS_EVENT_PENDING 2989
@@ -367,7 +384,7 @@ static void icnss_pm_stay_awake(struct icnss_priv *priv)
if (atomic_inc_return(&priv->pm_count) != 1)
return;
- icnss_pr_dbg("PM stay awake, state: 0x%lx, count: %d\n", priv->state,
+ icnss_pr_vdbg("PM stay awake, state: 0x%lx, count: %d\n", priv->state,
atomic_read(&priv->pm_count));
pm_stay_awake(&priv->pdev->dev);
@@ -384,7 +401,7 @@ static void icnss_pm_relax(struct icnss_priv *priv)
if (r != 0)
return;
- icnss_pr_dbg("PM relax, state: 0x%lx, count: %d\n", priv->state,
+ icnss_pr_vdbg("PM relax, state: 0x%lx, count: %d\n", priv->state,
atomic_read(&priv->pm_count));
pm_relax(&priv->pdev->dev);
@@ -718,7 +735,7 @@ static int icnss_vreg_on(struct icnss_priv *priv)
if (!vreg_info->reg)
continue;
- icnss_pr_dbg("Regulator %s being enabled\n", vreg_info->name);
+ icnss_pr_vdbg("Regulator %s being enabled\n", vreg_info->name);
ret = regulator_set_voltage(vreg_info->reg, vreg_info->min_v,
vreg_info->max_v);
@@ -780,7 +797,7 @@ static int icnss_vreg_off(struct icnss_priv *priv)
if (!vreg_info->reg)
continue;
- icnss_pr_dbg("Regulator %s being disabled\n", vreg_info->name);
+ icnss_pr_vdbg("Regulator %s being disabled\n", vreg_info->name);
ret = regulator_disable(vreg_info->reg);
if (ret)
@@ -814,7 +831,7 @@ static int icnss_clk_init(struct icnss_priv *priv)
if (!clk_info->handle)
continue;
- icnss_pr_dbg("Clock %s being enabled\n", clk_info->name);
+ icnss_pr_vdbg("Clock %s being enabled\n", clk_info->name);
if (clk_info->freq) {
ret = clk_set_rate(clk_info->handle, clk_info->freq);
@@ -861,7 +878,7 @@ static int icnss_clk_deinit(struct icnss_priv *priv)
if (!clk_info->handle)
continue;
- icnss_pr_dbg("Clock %s being disabled\n", clk_info->name);
+ icnss_pr_vdbg("Clock %s being disabled\n", clk_info->name);
clk_disable_unprepare(clk_info->handle);
}
@@ -1734,7 +1751,7 @@ static void icnss_qmi_wlfw_clnt_notify_work(struct work_struct *work)
if (!penv || !penv->wlfw_clnt)
return;
- icnss_pr_dbg("Receiving Event in work queue context\n");
+ icnss_pr_vdbg("Receiving Event in work queue context\n");
do {
} while ((ret = qmi_recv_msg(penv->wlfw_clnt)) == 0);
@@ -1742,13 +1759,13 @@ static void icnss_qmi_wlfw_clnt_notify_work(struct work_struct *work)
if (ret != -ENOMSG)
icnss_pr_err("Error receiving message: %d\n", ret);
- icnss_pr_dbg("Receiving Event completed\n");
+ icnss_pr_vdbg("Receiving Event completed\n");
}
static void icnss_qmi_wlfw_clnt_notify(struct qmi_handle *handle,
enum qmi_event_type event, void *notify_priv)
{
- icnss_pr_dbg("QMI client notify: %d\n", event);
+ icnss_pr_vdbg("QMI client notify: %d\n", event);
if (!penv || !penv->wlfw_clnt)
return;
@@ -1763,11 +1780,29 @@ static void icnss_qmi_wlfw_clnt_notify(struct qmi_handle *handle,
}
}
+static int icnss_call_driver_uevent(struct icnss_priv *priv,
+ enum icnss_uevent uevent, void *data)
+{
+ struct icnss_uevent_data uevent_data;
+
+ if (!priv->ops || !priv->ops->uevent)
+ return 0;
+
+ icnss_pr_dbg("Calling driver uevent state: 0x%lx, uevent: %d\n",
+ priv->state, uevent);
+
+ uevent_data.uevent = uevent;
+ uevent_data.data = data;
+
+ return priv->ops->uevent(&priv->pdev->dev, &uevent_data);
+}
+
static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle,
unsigned int msg_id, void *msg,
unsigned int msg_len, void *ind_cb_priv)
{
struct icnss_event_pd_service_down_data *event_data;
+ struct icnss_uevent_fw_down_data fw_down_data;
if (!penv)
return;
@@ -1799,6 +1834,9 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle,
return;
event_data->crashed = true;
event_data->fw_rejuvenate = true;
+ fw_down_data.crashed = true;
+ icnss_call_driver_uevent(penv, ICNSS_UEVENT_FW_DOWN,
+ &fw_down_data);
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
0, event_data);
break;
@@ -1912,23 +1950,6 @@ static int icnss_driver_event_server_exit(void *data)
return 0;
}
-static int icnss_call_driver_uevent(struct icnss_priv *priv,
- enum icnss_uevent uevent, void *data)
-{
- struct icnss_uevent_data uevent_data;
-
- if (!priv->ops || !priv->ops->uevent)
- return 0;
-
- icnss_pr_dbg("Calling driver uevent state: 0x%lx, uevent: %d\n",
- priv->state, uevent);
-
- uevent_data.uevent = uevent;
- uevent_data.data = data;
-
- return priv->ops->uevent(&priv->pdev->dev, &uevent_data);
-}
-
static int icnss_call_driver_probe(struct icnss_priv *priv)
{
int ret;
@@ -1947,6 +1968,8 @@ 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;
}
@@ -2076,6 +2099,8 @@ 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;
}
@@ -2101,6 +2126,8 @@ 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;
@@ -2125,6 +2152,8 @@ 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);
@@ -2142,7 +2171,8 @@ static int icnss_fw_crashed(struct icnss_priv *priv,
icnss_pm_stay_awake(priv);
- icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL);
+ if (test_bit(ICNSS_DRIVER_PROBED, &priv->state))
+ icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL);
if (event_data->wdog_bite) {
set_bit(ICNSS_WDOG_BITE, &priv->state);
@@ -2308,8 +2338,9 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
struct notif_data *notif = data;
struct icnss_priv *priv = container_of(nb, struct icnss_priv,
modem_ssr_nb);
+ struct icnss_uevent_fw_down_data fw_down_data;
- icnss_pr_dbg("Modem-Notify: event %lu\n", code);
+ icnss_pr_vdbg("Modem-Notify: event %lu\n", code);
if (code == SUBSYS_AFTER_SHUTDOWN &&
notif->crashed == CRASH_STATUS_ERR_FATAL) {
@@ -2340,6 +2371,9 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
if (notif->crashed == CRASH_STATUS_WDOG_BITE)
event_data->wdog_bite = true;
+ fw_down_data.crashed = !!notif->crashed;
+ icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data);
+
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
ICNSS_EVENT_SYNC, event_data);
@@ -2403,6 +2437,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
service_notifier_nb);
enum pd_subsys_state *state = data;
struct icnss_event_pd_service_down_data *event_data;
+ struct icnss_uevent_fw_down_data fw_down_data;
icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n",
notification, priv->state);
@@ -2438,6 +2473,8 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
event_post:
icnss_ignore_qmi_timeout(true);
+ fw_down_data.crashed = event_data->crashed;
+ icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data);
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
ICNSS_EVENT_SYNC, event_data);
done:
@@ -2656,7 +2693,7 @@ int icnss_ce_request_irq(unsigned int ce_id,
goto out;
}
- icnss_pr_dbg("CE request IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
+ icnss_pr_vdbg("CE request IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
icnss_pr_err("Invalid CE ID, ce_id: %d\n", ce_id);
@@ -2682,7 +2719,7 @@ int icnss_ce_request_irq(unsigned int ce_id,
irq_entry->irq = irq;
irq_entry->handler = handler;
- icnss_pr_dbg("IRQ requested: %d, ce_id: %d\n", irq, ce_id);
+ icnss_pr_vdbg("IRQ requested: %d, ce_id: %d\n", irq, ce_id);
penv->stats.ce_irqs[ce_id].request++;
out:
@@ -2701,7 +2738,7 @@ int icnss_ce_free_irq(unsigned int ce_id, void *ctx)
goto out;
}
- icnss_pr_dbg("CE free IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
+ icnss_pr_vdbg("CE free IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
icnss_pr_err("Invalid CE ID to free, ce_id: %d\n", ce_id);
@@ -2735,7 +2772,7 @@ void icnss_enable_irq(unsigned int ce_id)
return;
}
- icnss_pr_dbg("Enable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
+ icnss_pr_vdbg("Enable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
penv->state);
if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
@@ -2759,7 +2796,7 @@ void icnss_disable_irq(unsigned int ce_id)
return;
}
- icnss_pr_dbg("Disable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
+ icnss_pr_vdbg("Disable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
penv->state);
if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
@@ -4259,7 +4296,7 @@ static int icnss_pm_suspend(struct device *dev)
return -EINVAL;
}
- icnss_pr_dbg("PM Suspend, state: 0x%lx\n", priv->state);
+ icnss_pr_vdbg("PM Suspend, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->pm_suspend ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -4288,7 +4325,7 @@ static int icnss_pm_resume(struct device *dev)
return -EINVAL;
}
- icnss_pr_dbg("PM resume, state: 0x%lx\n", priv->state);
+ icnss_pr_vdbg("PM resume, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->pm_resume ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -4317,7 +4354,7 @@ static int icnss_pm_suspend_noirq(struct device *dev)
return -EINVAL;
}
- icnss_pr_dbg("PM suspend_noirq, state: 0x%lx\n", priv->state);
+ icnss_pr_vdbg("PM suspend_noirq, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->suspend_noirq ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -4346,7 +4383,7 @@ static int icnss_pm_resume_noirq(struct device *dev)
return -EINVAL;
}
- icnss_pr_dbg("PM resume_noirq, state: 0x%lx\n", priv->state);
+ icnss_pr_vdbg("PM resume_noirq, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->resume_noirq ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -4397,6 +4434,11 @@ static int __init icnss_initialize(void)
if (!icnss_ipc_log_context)
icnss_pr_err("Unable to create log context\n");
+ icnss_ipc_log_long_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
+ "icnss_long", 0);
+ if (!icnss_ipc_log_long_context)
+ icnss_pr_err("Unable to create log long context\n");
+
return platform_driver_register(&icnss_driver);
}
@@ -4405,6 +4447,8 @@ static void __exit icnss_exit(void)
platform_driver_unregister(&icnss_driver);
ipc_log_context_destroy(icnss_ipc_log_context);
icnss_ipc_log_context = NULL;
+ ipc_log_context_destroy(icnss_ipc_log_long_context);
+ icnss_ipc_log_long_context = NULL;
}
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c b/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c
index 10fb4cc8ebff..aafe82f59b9a 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_arb_adhoc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is Mree software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1349,6 +1349,7 @@ static void unregister_adhoc(struct msm_bus_client_handle *cl)
cl->first_hop, cl->active_only);
commit_data();
msm_bus_dbg_remove_client(cl);
+ kfree(cl->name);
kfree(cl);
exit_unregister_client:
rt_mutex_unlock(&msm_bus_adhoc_lock);
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_adhoc.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_adhoc.c
index 06657a666f2e..305f31f31bf8 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_adhoc.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_adhoc.c
@@ -531,7 +531,7 @@ static int msm_bus_enable_node_qos_clk(struct msm_bus_node_device_type *node)
{
struct msm_bus_node_device_type *bus_node = NULL;
int i;
- int ret;
+ int ret = 0;
long rounded_rate;
if (!node || (!to_msm_bus_node(node->node_info->bus_device))) {
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index c252fa9d1a96..6e5ddc4a3a7d 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -465,6 +465,8 @@ static int pil_alloc_region(struct pil_priv *priv, phys_addr_t min_addr,
if (region == NULL) {
pil_err(priv->desc, "Failed to allocate relocatable region of size %zx\n",
size);
+ priv->region_start = 0;
+ priv->region_end = 0;
return -ENOMEM;
}
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
index d11ffdde23be..3a6d84140bc9 100644
--- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
+++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
@@ -98,8 +98,7 @@ static int __apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data,
unsigned long flags;
spin_lock_irqsave(&apr_ch->w_lock, flags);
- rc = glink_tx(apr_ch->handle, pkt_priv, data, len,
- GLINK_TX_REQ_INTENT | GLINK_TX_ATOMIC);
+ rc = glink_tx(apr_ch->handle, pkt_priv, data, len, GLINK_TX_ATOMIC);
spin_unlock_irqrestore(&apr_ch->w_lock, flags);
if (rc)
diff --git a/drivers/soc/qcom/qdsp6v2/audio_notifier.c b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
index b120883afbb0..a59b436234c7 100644
--- a/drivers/soc/qcom/qdsp6v2/audio_notifier.c
+++ b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
@@ -626,9 +626,11 @@ static int __init audio_notifier_late_init(void)
* If pdr registration failed, register clients on next service
* Do in late init to ensure that SSR subsystem is initialized
*/
+ mutex_lock(&notifier_mutex);
if (!audio_notifer_is_service_enabled(AUDIO_NOTIFIER_PDR_SERVICE))
audio_notifer_reg_all_clients();
+ mutex_unlock(&notifier_mutex);
return 0;
}
late_initcall(audio_notifier_late_init);
diff --git a/drivers/soc/qcom/qpnp-haptic.c b/drivers/soc/qcom/qpnp-haptic.c
index f0f9306ebe47..c86eebcd390f 100644
--- a/drivers/soc/qcom/qpnp-haptic.c
+++ b/drivers/soc/qcom/qpnp-haptic.c
@@ -64,6 +64,7 @@
#define QPNP_HAP_ACT_TYPE_MASK BIT(0)
#define QPNP_HAP_LRA 0x0
#define QPNP_HAP_ERM 0x1
+#define QPNP_HAP_PM660_HW_AUTO_RES_MODE_BIT BIT(3)
#define QPNP_HAP_AUTO_RES_MODE_MASK GENMASK(6, 4)
#define QPNP_HAP_AUTO_RES_MODE_SHIFT 4
#define QPNP_HAP_PM660_AUTO_RES_MODE_BIT BIT(7)
@@ -308,6 +309,7 @@ struct qpnp_pwm_info {
* @ reg_play - play register
* @ lra_res_cal_period - period for resonance calibration
* @ sc_duration - counter to determine the duration of short circuit condition
+ * @ lra_hw_auto_resonance - enable hardware auto resonance
* @ state - current state of haptics
* @ wf_update - waveform update flag
* @ pwm_cfg_state - pwm mode configuration state
@@ -373,6 +375,7 @@ struct qpnp_hap {
u8 pmic_subtype;
u8 auto_res_mode;
u8 clk_trim_error_code;
+ bool lra_hw_auto_resonance;
bool vcc_pon_enabled;
bool state;
bool manage_pon_supply;
@@ -724,6 +727,15 @@ static int qpnp_hap_lra_auto_res_config(struct qpnp_hap *hap)
return rc;
}
+ if (hap->lra_hw_auto_resonance) {
+ rc = qpnp_hap_masked_write_reg(hap,
+ QPNP_HAP_PM660_HW_AUTO_RES_MODE_BIT,
+ QPNP_HAP_AUTO_RES_CTRL(hap->base),
+ QPNP_HAP_PM660_HW_AUTO_RES_MODE_BIT);
+ if (rc)
+ return rc;
+ }
+
if (hap->lra_res_cal_period < QPNP_HAP_RES_CAL_PERIOD_MIN)
hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MIN;
@@ -1628,7 +1640,8 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on)
return rc;
}
if (hap->act_type == QPNP_HAP_LRA &&
- hap->correct_lra_drive_freq) {
+ hap->correct_lra_drive_freq &&
+ !hap->lra_hw_auto_resonance) {
/*
* Start timer to poll Auto Resonance error bit
*/
@@ -1646,13 +1659,15 @@ static int qpnp_hap_set(struct qpnp_hap *hap, int on)
if (hap->act_type == QPNP_HAP_LRA &&
hap->correct_lra_drive_freq &&
- (hap->status_flags & AUTO_RESONANCE_ENABLED)) {
+ (hap->status_flags & AUTO_RESONANCE_ENABLED) &&
+ !hap->lra_hw_auto_resonance) {
update_lra_frequency(hap);
}
rc = qpnp_hap_mod_enable(hap, on);
if (hap->act_type == QPNP_HAP_LRA &&
- hap->correct_lra_drive_freq) {
+ hap->correct_lra_drive_freq &&
+ !hap->lra_hw_auto_resonance) {
hrtimer_cancel(&hap->auto_res_err_poll_timer);
}
}
@@ -1670,7 +1685,8 @@ static void qpnp_hap_td_enable(struct timed_output_dev *dev, int value)
mutex_lock(&hap->lock);
if (hap->act_type == QPNP_HAP_LRA &&
- hap->correct_lra_drive_freq)
+ hap->correct_lra_drive_freq &&
+ !hap->lra_hw_auto_resonance)
hrtimer_cancel(&hap->auto_res_err_poll_timer);
hrtimer_cancel(&hap->hap_timer);
@@ -2199,6 +2215,10 @@ static int qpnp_hap_parse_dt(struct qpnp_hap *hap)
return rc;
}
+ hap->lra_hw_auto_resonance =
+ of_property_read_bool(pdev->dev.of_node,
+ "qcom,lra-hw-auto-resonance");
+
hap->perform_lra_auto_resonance_search =
of_property_read_bool(pdev->dev.of_node,
"qcom,perform-lra-auto-resonance-search");
@@ -2453,7 +2473,8 @@ static int qpnp_haptic_probe(struct platform_device *pdev)
hap->timed_dev.get_time = qpnp_hap_get_time;
hap->timed_dev.enable = qpnp_hap_td_enable;
- if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq) {
+ if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq &&
+ !hap->lra_hw_auto_resonance) {
hrtimer_init(&hap->auto_res_err_poll_timer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL);
hap->auto_res_err_poll_timer.function = detect_auto_res_error;
@@ -2495,7 +2516,8 @@ sysfs_fail:
timed_output_dev_unregister(&hap->timed_dev);
timed_output_fail:
cancel_work_sync(&hap->work);
- if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq)
+ if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq &&
+ !hap->lra_hw_auto_resonance)
hrtimer_cancel(&hap->auto_res_err_poll_timer);
hrtimer_cancel(&hap->hap_timer);
mutex_destroy(&hap->lock);
@@ -2514,7 +2536,8 @@ static int qpnp_haptic_remove(struct platform_device *pdev)
&qpnp_hap_attrs[i].attr);
cancel_work_sync(&hap->work);
- if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq)
+ if (hap->act_type == QPNP_HAP_LRA && hap->correct_lra_drive_freq &&
+ !hap->lra_hw_auto_resonance)
hrtimer_cancel(&hap->auto_res_err_poll_timer);
hrtimer_cancel(&hap->hap_timer);
timed_output_dev_unregister(&hap->timed_dev);
diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c
index 0d6c1d62c732..0625f75de373 100644
--- a/drivers/soc/qcom/service-locator.c
+++ b/drivers/soc/qcom/service-locator.c
@@ -266,8 +266,10 @@ static int service_locator_send_msg(struct pd_qmi_client_data *pd)
if (!domains_read) {
db_rev_count = pd->db_rev_count = resp->db_rev_count;
pd->total_domains = resp->total_domains;
- if (!resp->total_domains)
- pr_info("No matching domains found\n");
+ if (!resp->total_domains) {
+ pr_err("No matching domains found\n");
+ goto out;
+ }
pd->domain_list = kmalloc(
sizeof(struct servreg_loc_entry_v01) *
@@ -375,6 +377,7 @@ int get_service_location(char *client_name, char *service_name,
if (!pqw) {
rc = -ENOMEM;
pr_err("Allocation failed\n");
+ kfree(pqcd);
goto err;
}
pqw->notifier = locator_nb;
diff --git a/drivers/soc/qcom/service-notifier.c b/drivers/soc/qcom/service-notifier.c
index e937848d7edf..fa916ac5ade4 100644
--- a/drivers/soc/qcom/service-notifier.c
+++ b/drivers/soc/qcom/service-notifier.c
@@ -104,6 +104,7 @@ struct qmi_client_info {
struct work_struct svc_exit;
struct work_struct svc_rcv_msg;
struct work_struct ind_ack;
+ struct work_struct qmi_handle_free;
struct workqueue_struct *svc_event_wq;
struct qmi_handle *clnt_handle;
struct notifier_block notifier;
@@ -123,6 +124,18 @@ static void root_service_clnt_recv_msg(struct work_struct *work);
static void root_service_service_arrive(struct work_struct *work);
static void root_service_exit_work(struct work_struct *work);
+static void free_qmi_handle(struct work_struct *work)
+{
+ struct qmi_client_info *data = container_of(work,
+ struct qmi_client_info, qmi_handle_free);
+
+ mutex_lock(&qmi_client_release_lock);
+ data->service_connected = false;
+ qmi_handle_destroy(data->clnt_handle);
+ data->clnt_handle = NULL;
+ mutex_unlock(&qmi_client_release_lock);
+}
+
static struct service_notif_info *_find_service_info(const char *service_path)
{
struct service_notif_info *service_notif;
@@ -426,11 +439,7 @@ static void root_service_service_exit(struct qmi_client_info *data,
* Destroy client handle and try connecting when
* service comes up again.
*/
- mutex_lock(&qmi_client_release_lock);
- data->service_connected = false;
- qmi_handle_destroy(data->clnt_handle);
- data->clnt_handle = NULL;
- mutex_unlock(&qmi_client_release_lock);
+ queue_work(data->svc_event_wq, &data->qmi_handle_free);
}
static void root_service_exit_work(struct work_struct *work)
@@ -486,7 +495,7 @@ static int ssr_event_notify(struct notifier_block *this,
info->subsys_state = ROOT_PD_SHUTDOWN;
break;
}
- queue_work(info->svc_event_wq, &info->svc_exit);
+ root_service_service_exit(info, info->subsys_state);
break;
default:
break;
@@ -561,6 +570,7 @@ static void *add_service_notif(const char *service_path, int instance_id,
INIT_WORK(&qmi_data->svc_exit, root_service_exit_work);
INIT_WORK(&qmi_data->svc_rcv_msg, root_service_clnt_recv_msg);
INIT_WORK(&qmi_data->ind_ack, send_ind_ack);
+ INIT_WORK(&qmi_data->qmi_handle_free, free_qmi_handle);
*curr_state = service_notif->curr_state =
SERVREG_NOTIF_SERVICE_STATE_UNINIT_V01;
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index 457361ba5ff8..0c44d76bc7c7 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -1744,7 +1744,9 @@ static int spcom_handle_lock_ion_buf_command(struct spcom_channel *ch,
}
}
- pr_err("fd [%d] ion buf not found.\n", fd);
+ pr_err("no free entry to store ion handle of fd [%d].\n", fd);
+ /* decrement back the ref count */
+ ion_free(spcom_dev->ion_client, ion_handle);
return -EFAULT;
}
diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c
index 1ceded4db79f..f601e6646852 100644
--- a/drivers/soc/qcom/wcd-dsp-glink.c
+++ b/drivers/soc/qcom/wcd-dsp-glink.c
@@ -531,6 +531,13 @@ static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv,
u8 *payload;
u32 ch_size, ch_cfg_size;
+ mutex_lock(&wpriv->glink_mutex);
+ if (wpriv->ch) {
+ dev_err(wpriv->dev, "%s: glink ch memory is already allocated\n",
+ __func__);
+ ret = -EINVAL;
+ goto done;
+ }
payload = (u8 *)pkt->payload;
no_of_channels = pkt->no_of_channels;
@@ -611,6 +618,7 @@ err_ch_mem:
wpriv->no_of_channels = 0;
done:
+ mutex_unlock(&wpriv->glink_mutex);
return ret;
}
diff --git a/drivers/soundwire/swr-wcd-ctrl.c b/drivers/soundwire/swr-wcd-ctrl.c
index 63bc3961de3b..e72663bd2138 100644
--- a/drivers/soundwire/swr-wcd-ctrl.c
+++ b/drivers/soundwire/swr-wcd-ctrl.c
@@ -224,6 +224,12 @@ static struct dentry *debugfs_poke;
static struct dentry *debugfs_reg_dump;
static unsigned int read_data;
+
+static bool swrm_is_msm_variant(int val)
+{
+ return (val == SWRM_VERSION_1_3);
+}
+
static int swrm_debug_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
@@ -514,8 +520,17 @@ static int swrm_cmd_fifo_wr_cmd(struct swr_mstr_ctrl *swrm, u8 cmd_data,
__func__, val, ret);
goto err;
}
- if (cmd_id == 0xF)
- wait_for_completion_timeout(&swrm->broadcast, (2 * HZ/10));
+ if (cmd_id == 0xF) {
+ /*
+ * sleep for 10ms for MSM soundwire variant to allow broadcast
+ * command to complete.
+ */
+ if (swrm_is_msm_variant(swrm->version))
+ usleep_range(10000, 10100);
+ else
+ wait_for_completion_timeout(&swrm->broadcast,
+ (2 * HZ/10));
+ }
err:
return ret;
}
@@ -1472,6 +1487,7 @@ static int swrm_probe(struct platform_device *pdev)
mutex_unlock(&swrm->mlock);
goto err_mstr_fail;
}
+ swrm->version = swrm->read(swrm->handle, SWRM_COMP_HW_VERSION);
/* Enumerate slave devices */
list_for_each_entry_safe(swr_dev, safe, &swrm->master.devices,
diff --git a/drivers/soundwire/swr-wcd-ctrl.h b/drivers/soundwire/swr-wcd-ctrl.h
index 8992318cdbd3..b7a3edac3e00 100755
--- a/drivers/soundwire/swr-wcd-ctrl.h
+++ b/drivers/soundwire/swr-wcd-ctrl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -23,6 +23,10 @@
#define SWR_MSTR_PORT_LEN 8 /* Number of master ports */
+#define SWRM_VERSION_1_0 0x01010000
+#define SWRM_VERSION_1_2 0x01030000
+#define SWRM_VERSION_1_3 0x01040000
+
enum {
SWR_MSTR_PAUSE,
SWR_MSTR_RESUME,
@@ -88,6 +92,7 @@ struct swr_mstr_ctrl {
int (*reg_irq)(void *handle, irqreturn_t(*irq_handler)(int irq,
void *data), void *swr_handle, int type);
int irq;
+ int version;
int num_enum_slaves;
int slave_status;
struct swr_mstr_port *mstr_port;
diff --git a/drivers/soundwire/swrm_registers.h b/drivers/soundwire/swrm_registers.h
index c6923f301f9f..50c3ecfdd47d 100755
--- a/drivers/soundwire/swrm_registers.h
+++ b/drivers/soundwire/swrm_registers.h
@@ -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
@@ -15,6 +15,7 @@
#define SWRM_BASE_ADDRESS 0x00
+#define SWRM_COMP_HW_VERSION SWRM_BASE_ADDRESS
#define SWRM_COMP_CFG_ADDR (SWRM_BASE_ADDRESS+0x00000004)
#define SWRM_COMP_CFG_RMSK 0x3
#define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_BMSK 0x2
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index b7fe42582e89..faa81c28a0d3 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -16,6 +16,7 @@
*
*/
+#include <linux/atomic.h>
#include <linux/err.h>
#include <linux/file.h>
#include <linux/freezer.h>
@@ -402,6 +403,15 @@ static void ion_handle_get(struct ion_handle *handle)
kref_get(&handle->ref);
}
+/* Must hold the client lock */
+static struct ion_handle* ion_handle_get_check_overflow(struct ion_handle *handle)
+{
+ if (atomic_read(&handle->ref.refcount) + 1 == 0)
+ return ERR_PTR(-EOVERFLOW);
+ ion_handle_get(handle);
+ return handle;
+}
+
static int ion_handle_put_nolock(struct ion_handle *handle)
{
int ret;
@@ -448,9 +458,9 @@ static struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client,
handle = idr_find(&client->idr, id);
if (handle)
- ion_handle_get(handle);
+ return ion_handle_get_check_overflow(handle);
- return handle ? handle : ERR_PTR(-EINVAL);
+ return ERR_PTR(-EINVAL);
}
struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
@@ -1412,7 +1422,7 @@ struct ion_handle *ion_import_dma_buf(struct ion_client *client, int fd)
/* if a handle exists for this buffer just take a reference to it */
handle = ion_handle_lookup(client, buffer);
if (!IS_ERR(handle)) {
- ion_handle_get(handle);
+ handle = ion_handle_get_check_overflow(handle);
mutex_unlock(&client->lock);
goto end;
}
diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c
index 03b2b8a38991..2ad4cc7a4785 100644
--- a/drivers/staging/android/ion/ion_system_heap.c
+++ b/drivers/staging/android/ion/ion_system_heap.c
@@ -2,7 +2,7 @@
* drivers/staging/android/ion/ion_system_heap.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
@@ -123,9 +123,11 @@ static struct page *alloc_buffer_page(struct ion_system_heap *heap,
gfp_t gfp_mask = low_order_gfp_flags;
if (order)
gfp_mask = high_order_gfp_flags;
+
page = alloc_pages(gfp_mask, order);
- ion_pages_sync_for_device(dev, page, PAGE_SIZE << order,
- DMA_BIDIRECTIONAL);
+ if (page)
+ ion_pages_sync_for_device(dev, page, PAGE_SIZE << order,
+ DMA_BIDIRECTIONAL);
}
if (!page)
return 0;
diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c
index 110b8c0b6cd7..0f2fe34e14c2 100644
--- a/drivers/staging/rtl8188eu/core/rtw_recv.c
+++ b/drivers/staging/rtl8188eu/core/rtw_recv.c
@@ -1405,6 +1405,9 @@ static int wlanhdr_to_ethhdr(struct recv_frame *precvframe)
ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
}
+ if (!ptr)
+ return _FAIL;
+
memcpy(ptr, pattrib->dst, ETH_ALEN);
memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN);
diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c
index 4ff530155187..04ac23cc47a8 100644
--- a/drivers/staging/rtl8712/rtl871x_recv.c
+++ b/drivers/staging/rtl8712/rtl871x_recv.c
@@ -641,11 +641,16 @@ sint r8712_wlanhdr_to_ethhdr(union recv_frame *precvframe)
/* append rx status for mp test packets */
ptr = recvframe_pull(precvframe, (rmv_len -
sizeof(struct ethhdr) + 2) - 24);
+ if (!ptr)
+ return _FAIL;
memcpy(ptr, get_rxmem(precvframe), 24);
ptr += 24;
- } else
+ } else {
ptr = recvframe_pull(precvframe, (rmv_len -
sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
+ if (!ptr)
+ return _FAIL;
+ }
memcpy(ptr, pattrib->dst, ETH_ALEN);
memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN);
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index bd810c109277..6ed80b05d674 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -3436,7 +3436,7 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
if ((tpg->tpg_attrib.generate_node_acls == 0) &&
(tpg->tpg_attrib.demo_mode_discovery == 0) &&
- (!core_tpg_get_initiator_node_acl(&tpg->tpg_se_tpg,
+ (!target_tpg_has_node_acl(&tpg->tpg_se_tpg,
cmd->conn->sess->sess_ops->InitiatorName))) {
continue;
}
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 356c80fbb304..bb6a6c35324a 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -77,12 +77,16 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u64 unpacked_lun)
&deve->read_bytes);
se_lun = rcu_dereference(deve->se_lun);
+
+ if (!percpu_ref_tryget_live(&se_lun->lun_ref)) {
+ se_lun = NULL;
+ goto out_unlock;
+ }
+
se_cmd->se_lun = rcu_dereference(deve->se_lun);
se_cmd->pr_res_key = deve->pr_res_key;
se_cmd->orig_fe_lun = unpacked_lun;
se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD;
-
- percpu_ref_get(&se_lun->lun_ref);
se_cmd->lun_ref_active = true;
if ((se_cmd->data_direction == DMA_TO_DEVICE) &&
@@ -96,6 +100,7 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u64 unpacked_lun)
goto ref_dev;
}
}
+out_unlock:
rcu_read_unlock();
if (!se_lun) {
@@ -826,6 +831,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
xcopy_lun = &dev->xcopy_lun;
rcu_assign_pointer(xcopy_lun->lun_se_dev, dev);
init_completion(&xcopy_lun->lun_ref_comp);
+ init_completion(&xcopy_lun->lun_shutdown_comp);
INIT_LIST_HEAD(&xcopy_lun->lun_deve_list);
INIT_LIST_HEAD(&xcopy_lun->lun_dev_link);
mutex_init(&xcopy_lun->lun_tg_pt_md_mutex);
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 5fb9dd7f08bb..2794c6ec5c3c 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -75,9 +75,21 @@ struct se_node_acl *core_tpg_get_initiator_node_acl(
unsigned char *initiatorname)
{
struct se_node_acl *acl;
-
+ /*
+ * Obtain se_node_acl->acl_kref using fabric driver provided
+ * initiatorname[] during node acl endpoint lookup driven by
+ * new se_session login.
+ *
+ * The reference is held until se_session shutdown -> release
+ * occurs via fabric driver invoked transport_deregister_session()
+ * or transport_free_session() code.
+ */
mutex_lock(&tpg->acl_node_mutex);
acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
+ if (acl) {
+ if (!kref_get_unless_zero(&acl->acl_kref))
+ acl = NULL;
+ }
mutex_unlock(&tpg->acl_node_mutex);
return acl;
@@ -232,6 +244,25 @@ static void target_add_node_acl(struct se_node_acl *acl)
acl->initiatorname);
}
+bool target_tpg_has_node_acl(struct se_portal_group *tpg,
+ const char *initiatorname)
+{
+ struct se_node_acl *acl;
+ bool found = false;
+
+ mutex_lock(&tpg->acl_node_mutex);
+ list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
+ if (!strcmp(acl->initiatorname, initiatorname)) {
+ found = true;
+ break;
+ }
+ }
+ mutex_unlock(&tpg->acl_node_mutex);
+
+ return found;
+}
+EXPORT_SYMBOL(target_tpg_has_node_acl);
+
struct se_node_acl *core_tpg_check_initiator_node_acl(
struct se_portal_group *tpg,
unsigned char *initiatorname)
@@ -248,6 +279,15 @@ struct se_node_acl *core_tpg_check_initiator_node_acl(
acl = target_alloc_node_acl(tpg, initiatorname);
if (!acl)
return NULL;
+ /*
+ * When allocating a dynamically generated node_acl, go ahead
+ * and take the extra kref now before returning to the fabric
+ * driver caller.
+ *
+ * Note this reference will be released at session shutdown
+ * time within transport_free_session() code.
+ */
+ kref_get(&acl->acl_kref);
acl->dynamic_node_acl = 1;
/*
@@ -499,7 +539,7 @@ static void core_tpg_lun_ref_release(struct percpu_ref *ref)
{
struct se_lun *lun = container_of(ref, struct se_lun, lun_ref);
- complete(&lun->lun_ref_comp);
+ complete(&lun->lun_shutdown_comp);
}
int core_tpg_register(
@@ -626,6 +666,7 @@ struct se_lun *core_tpg_alloc_lun(
lun->lun_link_magic = SE_LUN_LINK_MAGIC;
atomic_set(&lun->lun_acl_count, 0);
init_completion(&lun->lun_ref_comp);
+ init_completion(&lun->lun_shutdown_comp);
INIT_LIST_HEAD(&lun->lun_deve_list);
INIT_LIST_HEAD(&lun->lun_dev_link);
atomic_set(&lun->lun_tg_pt_secondary_offline, 0);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index aa517c4fadb9..df2059984e14 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -341,7 +341,6 @@ void __transport_register_session(
&buf[0], PR_REG_ISID_LEN);
se_sess->sess_bin_isid = get_unaligned_be64(&buf[0]);
}
- kref_get(&se_nacl->acl_kref);
spin_lock_irq(&se_nacl->nacl_sess_lock);
/*
@@ -424,14 +423,27 @@ static void target_complete_nacl(struct kref *kref)
{
struct se_node_acl *nacl = container_of(kref,
struct se_node_acl, acl_kref);
+ struct se_portal_group *se_tpg = nacl->se_tpg;
- complete(&nacl->acl_free_comp);
+ if (!nacl->dynamic_stop) {
+ complete(&nacl->acl_free_comp);
+ return;
+ }
+
+ mutex_lock(&se_tpg->acl_node_mutex);
+ list_del(&nacl->acl_list);
+ mutex_unlock(&se_tpg->acl_node_mutex);
+
+ core_tpg_wait_for_nacl_pr_ref(nacl);
+ core_free_device_list_for_node(nacl, se_tpg);
+ kfree(nacl);
}
void target_put_nacl(struct se_node_acl *nacl)
{
kref_put(&nacl->acl_kref, target_complete_nacl);
}
+EXPORT_SYMBOL(target_put_nacl);
void transport_deregister_session_configfs(struct se_session *se_sess)
{
@@ -464,6 +476,42 @@ EXPORT_SYMBOL(transport_deregister_session_configfs);
void transport_free_session(struct se_session *se_sess)
{
+ struct se_node_acl *se_nacl = se_sess->se_node_acl;
+
+ /*
+ * Drop the se_node_acl->nacl_kref obtained from within
+ * core_tpg_get_initiator_node_acl().
+ */
+ if (se_nacl) {
+ struct se_portal_group *se_tpg = se_nacl->se_tpg;
+ const struct target_core_fabric_ops *se_tfo = se_tpg->se_tpg_tfo;
+ unsigned long flags;
+
+ se_sess->se_node_acl = NULL;
+
+ /*
+ * Also determine if we need to drop the extra ->cmd_kref if
+ * it had been previously dynamically generated, and
+ * the endpoint is not caching dynamic ACLs.
+ */
+ mutex_lock(&se_tpg->acl_node_mutex);
+ if (se_nacl->dynamic_node_acl &&
+ !se_tfo->tpg_check_demo_mode_cache(se_tpg)) {
+ spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags);
+ if (list_empty(&se_nacl->acl_sess_list))
+ se_nacl->dynamic_stop = true;
+ spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags);
+
+ if (se_nacl->dynamic_stop)
+ list_del(&se_nacl->acl_list);
+ }
+ mutex_unlock(&se_tpg->acl_node_mutex);
+
+ if (se_nacl->dynamic_stop)
+ target_put_nacl(se_nacl);
+
+ target_put_nacl(se_nacl);
+ }
if (se_sess->sess_cmd_map) {
percpu_ida_destroy(&se_sess->sess_tag_pool);
kvfree(se_sess->sess_cmd_map);
@@ -475,16 +523,12 @@ EXPORT_SYMBOL(transport_free_session);
void transport_deregister_session(struct se_session *se_sess)
{
struct se_portal_group *se_tpg = se_sess->se_tpg;
- const struct target_core_fabric_ops *se_tfo;
- struct se_node_acl *se_nacl;
unsigned long flags;
- bool comp_nacl = true, drop_nacl = false;
if (!se_tpg) {
transport_free_session(se_sess);
return;
}
- se_tfo = se_tpg->se_tpg_tfo;
spin_lock_irqsave(&se_tpg->session_lock, flags);
list_del(&se_sess->sess_list);
@@ -492,37 +536,16 @@ void transport_deregister_session(struct se_session *se_sess)
se_sess->fabric_sess_ptr = NULL;
spin_unlock_irqrestore(&se_tpg->session_lock, flags);
- /*
- * Determine if we need to do extra work for this initiator node's
- * struct se_node_acl if it had been previously dynamically generated.
- */
- se_nacl = se_sess->se_node_acl;
-
- mutex_lock(&se_tpg->acl_node_mutex);
- if (se_nacl && se_nacl->dynamic_node_acl) {
- if (!se_tfo->tpg_check_demo_mode_cache(se_tpg)) {
- list_del(&se_nacl->acl_list);
- se_tpg->num_node_acls--;
- drop_nacl = true;
- }
- }
- mutex_unlock(&se_tpg->acl_node_mutex);
-
- if (drop_nacl) {
- core_tpg_wait_for_nacl_pr_ref(se_nacl);
- core_free_device_list_for_node(se_nacl, se_tpg);
- kfree(se_nacl);
- comp_nacl = false;
- }
pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n",
se_tpg->se_tpg_tfo->get_fabric_name());
/*
* If last kref is dropping now for an explicit NodeACL, awake sleeping
* ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group
- * removal context.
+ * removal context from within transport_free_session() code.
+ *
+ * For dynamic ACL, target_put_nacl() uses target_complete_nacl()
+ * to release all remaining generate_node_acl=1 created ACL resources.
*/
- if (se_nacl && comp_nacl)
- target_put_nacl(se_nacl);
transport_free_session(se_sess);
}
@@ -2657,10 +2680,39 @@ void target_wait_for_sess_cmds(struct se_session *se_sess)
}
EXPORT_SYMBOL(target_wait_for_sess_cmds);
+static void target_lun_confirm(struct percpu_ref *ref)
+{
+ struct se_lun *lun = container_of(ref, struct se_lun, lun_ref);
+
+ complete(&lun->lun_ref_comp);
+}
+
void transport_clear_lun_ref(struct se_lun *lun)
{
- percpu_ref_kill(&lun->lun_ref);
+ /*
+ * Mark the percpu-ref as DEAD, switch to atomic_t mode, drop
+ * the initial reference and schedule confirm kill to be
+ * executed after one full RCU grace period has completed.
+ */
+ percpu_ref_kill_and_confirm(&lun->lun_ref, target_lun_confirm);
+ /*
+ * The first completion waits for percpu_ref_switch_to_atomic_rcu()
+ * to call target_lun_confirm after lun->lun_ref has been marked
+ * as __PERCPU_REF_DEAD on all CPUs, and switches to atomic_t
+ * mode so that percpu_ref_tryget_live() lookup of lun->lun_ref
+ * fails for all new incoming I/O.
+ */
wait_for_completion(&lun->lun_ref_comp);
+ /*
+ * The second completion waits for percpu_ref_put_many() to
+ * invoke ->release() after lun->lun_ref has switched to
+ * atomic_t mode, and lun->lun_ref.count has reached zero.
+ *
+ * At this point all target-core lun->lun_ref references have
+ * been dropped via transport_lun_remove_cmd(), and it's safe
+ * to proceed with the remaining LUN shutdown.
+ */
+ wait_for_completion(&lun->lun_shutdown_comp);
}
static bool
diff --git a/drivers/thermal/msm_thermal-dev.c b/drivers/thermal/msm_thermal-dev.c
index e6af6b884e99..ead9765666c8 100644
--- a/drivers/thermal/msm_thermal-dev.c
+++ b/drivers/thermal/msm_thermal-dev.c
@@ -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
@@ -35,6 +35,7 @@ static unsigned int freq_table_len[NR_CPUS], freq_table_set[NR_CPUS];
static unsigned int voltage_table_set[NR_CPUS];
static unsigned int *freq_table_ptr[NR_CPUS];
static uint32_t *voltage_table_ptr[NR_CPUS];
+static DEFINE_MUTEX(ioctl_access_mutex);
static int msm_thermal_ioctl_open(struct inode *node, struct file *filep)
{
@@ -291,8 +292,9 @@ static long msm_thermal_ioctl_process(struct file *filep, unsigned int cmd,
ret = validate_and_copy(&cmd, &arg, &query);
if (ret)
- goto process_exit;
+ return ret;
+ mutex_lock(&ioctl_access_mutex);
switch (cmd) {
case MSM_THERMAL_SET_CPU_MAX_FREQUENCY:
ret = msm_thermal_set_frequency(query.cpu_freq.cpu_num,
@@ -321,6 +323,7 @@ static long msm_thermal_ioctl_process(struct file *filep, unsigned int cmd,
goto process_exit;
}
process_exit:
+ mutex_unlock(&ioctl_access_mutex);
return ret;
}
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index 644ddb841d9f..6d1e2f746ab4 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -114,7 +114,7 @@
#define DEFAULT_TX_BUF_COUNT 3
struct n_hdlc_buf {
- struct n_hdlc_buf *link;
+ struct list_head list_item;
int count;
char buf[1];
};
@@ -122,8 +122,7 @@ struct n_hdlc_buf {
#define N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe)
struct n_hdlc_buf_list {
- struct n_hdlc_buf *head;
- struct n_hdlc_buf *tail;
+ struct list_head list;
int count;
spinlock_t spinlock;
};
@@ -136,7 +135,6 @@ struct n_hdlc_buf_list {
* @backup_tty - TTY to use if tty gets closed
* @tbusy - reentrancy flag for tx wakeup code
* @woke_up - FIXME: describe this field
- * @tbuf - currently transmitting tx buffer
* @tx_buf_list - list of pending transmit frame buffers
* @rx_buf_list - list of received frame buffers
* @tx_free_buf_list - list unused transmit frame buffers
@@ -149,7 +147,6 @@ struct n_hdlc {
struct tty_struct *backup_tty;
int tbusy;
int woke_up;
- struct n_hdlc_buf *tbuf;
struct n_hdlc_buf_list tx_buf_list;
struct n_hdlc_buf_list rx_buf_list;
struct n_hdlc_buf_list tx_free_buf_list;
@@ -159,7 +156,8 @@ struct n_hdlc {
/*
* HDLC buffer list manipulation functions
*/
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list);
+static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
+ struct n_hdlc_buf *buf);
static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
struct n_hdlc_buf *buf);
static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
@@ -209,16 +207,9 @@ static void flush_tx_queue(struct tty_struct *tty)
{
struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
struct n_hdlc_buf *buf;
- unsigned long flags;
while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
- spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
- if (n_hdlc->tbuf) {
- n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
- n_hdlc->tbuf = NULL;
- }
- spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
}
static struct tty_ldisc_ops n_hdlc_ldisc = {
@@ -284,7 +275,6 @@ static void n_hdlc_release(struct n_hdlc *n_hdlc)
} else
break;
}
- kfree(n_hdlc->tbuf);
kfree(n_hdlc);
} /* end of n_hdlc_release() */
@@ -403,13 +393,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
n_hdlc->woke_up = 0;
spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
- /* get current transmit buffer or get new transmit */
- /* buffer from list of pending transmit buffers */
-
- tbuf = n_hdlc->tbuf;
- if (!tbuf)
- tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-
+ tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
while (tbuf) {
if (debuglevel >= DEBUG_LEVEL_INFO)
printk("%s(%d)sending frame %p, count=%d\n",
@@ -421,7 +405,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
/* rollback was possible and has been done */
if (actual == -ERESTARTSYS) {
- n_hdlc->tbuf = tbuf;
+ n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
break;
}
/* if transmit error, throw frame away by */
@@ -436,10 +420,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
/* free current transmit buffer */
n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
-
- /* this tx buffer is done */
- n_hdlc->tbuf = NULL;
-
+
/* wait up sleeping writers */
wake_up_interruptible(&tty->write_wait);
@@ -449,10 +430,12 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
if (debuglevel >= DEBUG_LEVEL_INFO)
printk("%s(%d)frame %p pending\n",
__FILE__,__LINE__,tbuf);
-
- /* buffer not accepted by driver */
- /* set this buffer as pending buffer */
- n_hdlc->tbuf = tbuf;
+
+ /*
+ * the buffer was not accepted by driver,
+ * return it back into tx queue
+ */
+ n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
break;
}
}
@@ -750,7 +733,8 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
int error = 0;
int count;
unsigned long flags;
-
+ struct n_hdlc_buf *buf = NULL;
+
if (debuglevel >= DEBUG_LEVEL_INFO)
printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
__FILE__,__LINE__,cmd);
@@ -764,8 +748,10 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
/* report count of read data available */
/* in next available frame (if any) */
spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
- if (n_hdlc->rx_buf_list.head)
- count = n_hdlc->rx_buf_list.head->count;
+ buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list,
+ struct n_hdlc_buf, list_item);
+ if (buf)
+ count = buf->count;
else
count = 0;
spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
@@ -777,8 +763,10 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
count = tty_chars_in_buffer(tty);
/* add size of next output frame in queue */
spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
- if (n_hdlc->tx_buf_list.head)
- count += n_hdlc->tx_buf_list.head->count;
+ buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list,
+ struct n_hdlc_buf, list_item);
+ if (buf)
+ count += buf->count;
spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
error = put_user(count, (int __user *)arg);
break;
@@ -826,14 +814,14 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
poll_wait(filp, &tty->write_wait, wait);
/* set bits for operations that won't block */
- if (n_hdlc->rx_buf_list.head)
+ if (!list_empty(&n_hdlc->rx_buf_list.list))
mask |= POLLIN | POLLRDNORM; /* readable */
if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
mask |= POLLHUP;
if (tty_hung_up_p(filp))
mask |= POLLHUP;
if (!tty_is_writelocked(tty) &&
- n_hdlc->tx_free_buf_list.head)
+ !list_empty(&n_hdlc->tx_free_buf_list.list))
mask |= POLLOUT | POLLWRNORM; /* writable */
}
return mask;
@@ -853,11 +841,16 @@ static struct n_hdlc *n_hdlc_alloc(void)
if (!n_hdlc)
return NULL;
- n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
- n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
- n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
- n_hdlc_buf_list_init(&n_hdlc->tx_buf_list);
-
+ spin_lock_init(&n_hdlc->rx_free_buf_list.spinlock);
+ spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock);
+ spin_lock_init(&n_hdlc->rx_buf_list.spinlock);
+ spin_lock_init(&n_hdlc->tx_buf_list.spinlock);
+
+ INIT_LIST_HEAD(&n_hdlc->rx_free_buf_list.list);
+ INIT_LIST_HEAD(&n_hdlc->tx_free_buf_list.list);
+ INIT_LIST_HEAD(&n_hdlc->rx_buf_list.list);
+ INIT_LIST_HEAD(&n_hdlc->tx_buf_list.list);
+
/* allocate free rx buffer list */
for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
@@ -885,63 +878,65 @@ static struct n_hdlc *n_hdlc_alloc(void)
} /* end of n_hdlc_alloc() */
/**
- * n_hdlc_buf_list_init - initialize specified HDLC buffer list
- * @list - pointer to buffer list
+ * n_hdlc_buf_return - put the HDLC buffer after the head of the specified list
+ * @buf_list - pointer to the buffer list
+ * @buf - pointer to the buffer
*/
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
+static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
+ struct n_hdlc_buf *buf)
{
- memset(list, 0, sizeof(*list));
- spin_lock_init(&list->spinlock);
-} /* end of n_hdlc_buf_list_init() */
+ unsigned long flags;
+
+ spin_lock_irqsave(&buf_list->spinlock, flags);
+
+ list_add(&buf->list_item, &buf_list->list);
+ buf_list->count++;
+
+ spin_unlock_irqrestore(&buf_list->spinlock, flags);
+}
/**
* n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
- * @list - pointer to buffer list
+ * @buf_list - pointer to buffer list
* @buf - pointer to buffer
*/
-static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
+static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list,
struct n_hdlc_buf *buf)
{
unsigned long flags;
- spin_lock_irqsave(&list->spinlock,flags);
-
- buf->link=NULL;
- if (list->tail)
- list->tail->link = buf;
- else
- list->head = buf;
- list->tail = buf;
- (list->count)++;
-
- spin_unlock_irqrestore(&list->spinlock,flags);
-
+
+ spin_lock_irqsave(&buf_list->spinlock, flags);
+
+ list_add_tail(&buf->list_item, &buf_list->list);
+ buf_list->count++;
+
+ spin_unlock_irqrestore(&buf_list->spinlock, flags);
} /* end of n_hdlc_buf_put() */
/**
* n_hdlc_buf_get - remove and return an HDLC buffer from list
- * @list - pointer to HDLC buffer list
+ * @buf_list - pointer to HDLC buffer list
*
* Remove and return an HDLC buffer from the head of the specified HDLC buffer
* list.
* Returns a pointer to HDLC buffer if available, otherwise %NULL.
*/
-static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
+static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list)
{
unsigned long flags;
struct n_hdlc_buf *buf;
- spin_lock_irqsave(&list->spinlock,flags);
-
- buf = list->head;
+
+ spin_lock_irqsave(&buf_list->spinlock, flags);
+
+ buf = list_first_entry_or_null(&buf_list->list,
+ struct n_hdlc_buf, list_item);
if (buf) {
- list->head = buf->link;
- (list->count)--;
+ list_del(&buf->list_item);
+ buf_list->count--;
}
- if (!list->head)
- list->tail = NULL;
-
- spin_unlock_irqrestore(&list->spinlock,flags);
+
+ spin_unlock_irqrestore(&buf_list->spinlock, flags);
return buf;
-
} /* end of n_hdlc_buf_get() */
static char hdlc_banner[] __initdata =
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 029de3f99752..5b24ffd93649 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -2880,6 +2880,8 @@ enum pci_board_num_t {
pbn_b0_4_1152000_200,
pbn_b0_8_1152000_200,
+ pbn_b0_4_1250000,
+
pbn_b0_2_1843200,
pbn_b0_4_1843200,
@@ -3113,6 +3115,13 @@ static struct pciserial_board pci_boards[] = {
.uart_offset = 0x200,
},
+ [pbn_b0_4_1250000] = {
+ .flags = FL_BASE0,
+ .num_ports = 4,
+ .base_baud = 1250000,
+ .uart_offset = 8,
+ },
+
[pbn_b0_2_1843200] = {
.flags = FL_BASE0,
.num_ports = 2,
@@ -5778,6 +5787,10 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_DEVICE(0x1c29, 0x1108), .driver_data = pbn_fintek_8 },
{ PCI_DEVICE(0x1c29, 0x1112), .driver_data = pbn_fintek_12 },
+ /* MKS Tenta SCOM-080x serial cards */
+ { PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 },
+ { PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000 },
+
/*
* These entries match devices with class COMMUNICATION_SERIAL,
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 8f68acd1d95d..db329230c7ca 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -1834,6 +1834,7 @@ static const struct of_device_id msm_match_table[] = {
{ .compatible = "qcom,msm-uartdm" },
{}
};
+MODULE_DEVICE_TABLE(of, msm_match_table);
#ifdef CONFIG_PM_SLEEP
static int msm_serial_suspend(struct device *dev)
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index f0d5c96ac2e0..830ef92ffe80 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -3,7 +3,7 @@
* MSM 7k High speed uart driver
*
* Copyright (c) 2008 Google Inc.
- * Copyright (c) 2007-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2007-2017, The Linux Foundation. All rights reserved.
* Modified: Nick Pelly <npelly@google.com>
*
* All source code in this file is licensed under the following license
@@ -1436,13 +1436,13 @@ static void msm_hs_submit_tx_locked(struct uart_port *uport)
hex_dump_ipc(msm_uport, tx->ipc_tx_ctxt, "Tx",
&tx_buf->buf[tx_buf->tail], (u64)src_addr, tx_count);
sps_pipe_handle = tx->cons.pipe_handle;
- /* Queue transfer request to SPS */
- ret = sps_transfer_one(sps_pipe_handle, src_addr, tx_count,
- msm_uport, flags);
/* Set 1 second timeout */
mod_timer(&tx->tx_timeout_timer,
jiffies + msecs_to_jiffies(MSEC_PER_SEC));
+ /* Queue transfer request to SPS */
+ ret = sps_transfer_one(sps_pipe_handle, src_addr, tx_count,
+ msm_uport, flags);
MSM_HS_DBG("%s:Enqueue Tx Cmd, ret %d\n", __func__, ret);
}
@@ -3155,6 +3155,11 @@ static void msm_hs_pm_suspend(struct device *dev)
mutex_lock(&msm_uport->mtx);
client_count = atomic_read(&msm_uport->client_count);
+ msm_uport->pm_state = MSM_HS_PM_SUSPENDED;
+ msm_hs_resource_off(msm_uport);
+ obs_manage_irq(msm_uport, false);
+ msm_hs_clk_bus_unvote(msm_uport);
+
/* For OBS, don't use wakeup interrupt, set gpio to suspended state */
if (msm_uport->obs) {
ret = pinctrl_select_state(msm_uport->pinctrl,
@@ -3164,10 +3169,6 @@ static void msm_hs_pm_suspend(struct device *dev)
__func__);
}
- msm_uport->pm_state = MSM_HS_PM_SUSPENDED;
- msm_hs_resource_off(msm_uport);
- obs_manage_irq(msm_uport, false);
- msm_hs_clk_bus_unvote(msm_uport);
if (!atomic_read(&msm_uport->client_req_state))
enable_wakeup_interrupt(msm_uport);
LOG_USR_MSG(msm_uport->ipc_msm_hs_pwr_ctxt,
@@ -3198,6 +3199,16 @@ static int msm_hs_pm_resume(struct device *dev)
goto exit_pm_resume;
if (!atomic_read(&msm_uport->client_req_state))
disable_wakeup_interrupt(msm_uport);
+
+ /* For OBS, don't use wakeup interrupt, set gpio to active state */
+ if (msm_uport->obs) {
+ ret = pinctrl_select_state(msm_uport->pinctrl,
+ msm_uport->gpio_state_active);
+ if (ret)
+ MSM_HS_ERR("%s():Error selecting active state",
+ __func__);
+ }
+
ret = msm_hs_clk_bus_vote(msm_uport);
if (ret) {
MSM_HS_ERR("%s:Failed clock vote %d\n", __func__, ret);
@@ -3208,15 +3219,6 @@ static int msm_hs_pm_resume(struct device *dev)
msm_uport->pm_state = MSM_HS_PM_ACTIVE;
msm_hs_resource_on(msm_uport);
- /* For OBS, don't use wakeup interrupt, set gpio to active state */
- if (msm_uport->obs) {
- ret = pinctrl_select_state(msm_uport->pinctrl,
- msm_uport->gpio_state_active);
- if (ret)
- MSM_HS_ERR("%s():Error selecting active state",
- __func__);
- }
-
LOG_USR_MSG(msm_uport->ipc_msm_hs_pwr_ctxt,
"%s:PM State:Active client_count %d\n", __func__, client_count);
exit_pm_resume:
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index ab8308ff7e69..cad76b1cf672 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -1030,8 +1030,10 @@ static int s3c64xx_serial_startup(struct uart_port *port)
if (ourport->dma) {
ret = s3c24xx_serial_request_dma(ourport);
if (ret < 0) {
- dev_warn(port->dev, "DMA request failed\n");
- return ret;
+ dev_warn(port->dev,
+ "DMA request failed, DMA will not be used\n");
+ devm_kfree(port->dev, ourport->dma);
+ ourport->dma = NULL;
}
}
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 5a048b7b92e8..2949289bb3c5 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -244,7 +244,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
struct ci_hdrc_platform_data pdata = {
.name = dev_name(&pdev->dev),
.capoffset = DEF_CAPOFFSET,
- .flags = CI_HDRC_SET_NON_ZERO_TTHA,
};
int ret;
const struct of_device_id *of_id;
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 5b648460e621..c2eba06f2ace 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -670,6 +670,16 @@ int dwc3_core_init(struct dwc3 *dwc)
}
}
+ /*
+ * Workaround for STAR 9000961433 which affects only version
+ * 3.00a of the DWC_usb3 core. This prevents the controller
+ * interrupt from being masked while handling events. IMOD
+ * allows us to work around this issue. Enable it for the
+ * affected version.
+ */
+ if (!dwc->imod_interval && (dwc->revision == DWC3_REVISION_300A))
+ dwc->imod_interval = 1;
+
ret = dwc3_core_reset(dwc);
if (ret)
goto err0;
@@ -1000,6 +1010,15 @@ err0:
#define DWC3_ALIGN_MASK (16 - 1)
+/* check whether the core supports IMOD */
+bool dwc3_has_imod(struct dwc3 *dwc)
+{
+ return ((dwc3_is_usb3(dwc) &&
+ dwc->revision >= DWC3_REVISION_300A) ||
+ (dwc3_is_usb31(dwc) &&
+ dwc->revision >= DWC3_USB31_REVISION_120A));
+}
+
static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1040,8 +1059,8 @@ static int dwc3_probe(struct platform_device *pdev)
/* will be enabled in dwc3_msm_resume() */
irq_set_status_flags(irq, IRQ_NOAUTOEN);
- ret = devm_request_threaded_irq(dev, irq, NULL, dwc3_interrupt,
- IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
+ ret = devm_request_irq(dev, irq, dwc3_interrupt, IRQF_SHARED, "dwc3",
+ dwc);
if (ret) {
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
irq, ret);
@@ -1219,6 +1238,14 @@ static int dwc3_probe(struct platform_device *pdev)
dev->dma_parms = dev->parent->dma_parms;
dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
+ dwc->dwc_wq = alloc_ordered_workqueue("dwc_wq", WQ_HIGHPRI);
+ if (!dwc->dwc_wq) {
+ pr_err("%s: Unable to create workqueue dwc_wq\n", __func__);
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&dwc->bh_work, dwc3_bh_work);
+
pm_runtime_no_callbacks(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
@@ -1284,6 +1311,7 @@ err0:
* memory region the next time probe is called.
*/
res->start -= DWC3_GLOBALS_REGS_START;
+ destroy_workqueue(dwc->dwc_wq);
return ret;
}
@@ -1313,6 +1341,8 @@ static int dwc3_remove(struct platform_device *pdev)
dwc3_core_exit(dwc);
dwc3_ulpi_exit(dwc);
+ destroy_workqueue(dwc->dwc_wq);
+
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index f6e2bea7b9aa..453eee734b23 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -66,6 +66,7 @@
#define DWC3_DEVICE_EVENT_OVERFLOW 11
#define DWC3_GEVNTCOUNT_MASK 0xfffc
+#define DWC3_GEVNTCOUNT_EHB (1 << 31)
#define DWC3_GSNPSID_MASK 0xffff0000
#define DWC3_GSNPSREV_MASK 0xffff
@@ -149,6 +150,8 @@
#define DWC3_DEPCMDPAR0(n) (0xc808 + (n * 0x10))
#define DWC3_DEPCMD(n) (0xc80c + (n * 0x10))
+#define DWC3_DEV_IMOD(n) (0xca00 + (n * 0x4))
+
/* OTG Registers */
#define DWC3_OCFG 0xcc00
#define DWC3_OCTL 0xcc04
@@ -433,6 +436,11 @@
#define DWC3_DEPCMD_TYPE_BULK 2
#define DWC3_DEPCMD_TYPE_INTR 3
+#define DWC3_DEV_IMOD_COUNT_SHIFT 16
+#define DWC3_DEV_IMOD_COUNT_MASK (0xffff << 16)
+#define DWC3_DEV_IMOD_INTERVAL_SHIFT 0
+#define DWC3_DEV_IMOD_INTERVAL_MASK (0xffff << 0)
+
/* Structures */
struct dwc3_trb;
@@ -837,6 +845,8 @@ struct dwc3_scratchpad_array {
* @bh_dbg_index: index for capturing bh_completion_time and bh_handled_evt_cnt
* @wait_linkstate: waitqueue for waiting LINK to move into required state
* @vbus_draw: current to be drawn from USB
+ * @imod_interval: set the interrupt moderation interval in 250ns
+ * increments or 0 to disable.
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
@@ -920,6 +930,7 @@ struct dwc3 {
#define DWC3_REVISION_260A 0x5533260a
#define DWC3_REVISION_270A 0x5533270a
#define DWC3_REVISION_280A 0x5533280a
+#define DWC3_REVISION_300A 0x5533300a
#define DWC3_REVISION_310A 0x5533310a
/*
@@ -928,6 +939,7 @@ struct dwc3 {
*/
#define DWC3_REVISION_IS_DWC31 0x80000000
#define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_USB31)
+#define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31)
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
@@ -1008,6 +1020,11 @@ struct dwc3 {
bool b_suspend;
unsigned vbus_draw;
+ u16 imod_interval;
+
+ struct workqueue_struct *dwc_wq;
+ struct work_struct bh_work;
+
/* IRQ timing statistics */
int irq;
unsigned long irq_cnt;
@@ -1175,6 +1192,20 @@ struct dwc3_gadget_ep_cmd_params {
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
+/* check whether we are on the DWC_usb3 core */
+static inline bool dwc3_is_usb3(struct dwc3 *dwc)
+{
+ return !(dwc->revision & DWC3_REVISION_IS_DWC31);
+}
+
+/* check whether we are on the DWC_usb31 core */
+static inline bool dwc3_is_usb31(struct dwc3 *dwc)
+{
+ return !!(dwc->revision & DWC3_REVISION_IS_DWC31);
+}
+
+bool dwc3_has_imod(struct dwc3 *dwc);
+
#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
int dwc3_host_init(struct dwc3 *dwc);
void dwc3_host_exit(struct dwc3 *dwc);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 623f3ce211aa..a80fb34cdce8 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -2053,6 +2053,9 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
if (dwc->irq)
disable_irq(dwc->irq);
+ if (work_busy(&dwc->bh_work))
+ dbg_event(0xFF, "pend evt", 0);
+
/* disable power event irq, hs and ss phy irq is used as wake up src */
disable_irq(mdwc->pwr_event_irq);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index e1284b6cc2ef..9608a79cbe40 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2011,6 +2011,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
int ret = 0;
u32 reg;
+ /*
+ * Use IMOD if enabled via dwc->imod_interval. Otherwise, if
+ * the core supports IMOD, disable it.
+ */
+ if (dwc->imod_interval) {
+ dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
+ } else if (dwc3_has_imod(dwc)) {
+ dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0);
+ }
+
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK);
@@ -3362,8 +3373,6 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
*/
evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
left -= 4;
-
- dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
}
dwc->bh_handled_evt_cnt[dwc->bh_dbg_index] += (evt->count / 4);
@@ -3377,9 +3386,22 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
reg &= ~DWC3_GEVNTSIZ_INTMASK;
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
+ if (dwc->imod_interval)
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf),
+ DWC3_GEVNTCOUNT_EHB);
+
return ret;
}
+void dwc3_bh_work(struct work_struct *w)
+{
+ struct dwc3 *dwc = container_of(w, struct dwc3, bh_work);
+
+ pm_runtime_get_sync(dwc->dev);
+ dwc3_thread_interrupt(dwc->irq, dwc);
+ pm_runtime_put(dwc->dev);
+}
+
static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
{
struct dwc3 *dwc = _dwc;
@@ -3434,6 +3456,8 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf)
reg |= DWC3_GEVNTSIZ_INTMASK;
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg);
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), count);
+
return IRQ_WAKE_THREAD;
}
@@ -3469,7 +3493,7 @@ irqreturn_t dwc3_interrupt(int irq, void *_dwc)
dwc->irq_dbg_index = (dwc->irq_dbg_index + 1) % MAX_INTR_STATS;
if (ret == IRQ_WAKE_THREAD)
- dwc3_thread_interrupt(dwc->irq, dwc);
+ queue_work(dwc->dwc_wq, &dwc->bh_work);
return IRQ_HANDLED;
}
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index a21962c8f513..baa83cf9638b 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -28,23 +28,23 @@ struct dwc3;
#define gadget_to_dwc(g) (container_of(g, struct dwc3, gadget))
/* DEPCFG parameter 1 */
-#define DWC3_DEPCFG_INT_NUM(n) ((n) << 0)
+#define DWC3_DEPCFG_INT_NUM(n) (((n) & 0x1f) << 0)
#define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8)
#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9)
#define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10)
#define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11)
#define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13)
-#define DWC3_DEPCFG_BINTERVAL_M1(n) ((n) << 16)
+#define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16)
#define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24)
-#define DWC3_DEPCFG_EP_NUMBER(n) ((n) << 25)
+#define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25)
#define DWC3_DEPCFG_BULK_BASED (1 << 30)
#define DWC3_DEPCFG_FIFO_BASED (1 << 31)
/* DEPCFG parameter 0 */
-#define DWC3_DEPCFG_EP_TYPE(n) ((n) << 1)
-#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) ((n) << 3)
-#define DWC3_DEPCFG_FIFO_NUMBER(n) ((n) << 17)
-#define DWC3_DEPCFG_BURST_SIZE(n) ((n) << 22)
+#define DWC3_DEPCFG_EP_TYPE(n) (((n) & 0x3) << 1)
+#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) (((n) & 0x7ff) << 3)
+#define DWC3_DEPCFG_FIFO_NUMBER(n) (((n) & 0x1f) << 17)
+#define DWC3_DEPCFG_BURST_SIZE(n) (((n) & 0xf) << 22)
#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26)
/* This applies for core versions earlier than 1.94a */
#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31)
@@ -105,6 +105,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);
irqreturn_t dwc3_interrupt(int irq, void *_dwc);
+void dwc3_bh_work(struct work_struct *w);
static inline dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
struct dwc3_trb *trb)
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index ed0ff7b1fc15..c31aaf7a9880 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -141,21 +141,28 @@ struct gadget_config_name {
struct list_head list;
};
+#define MAX_USB_STRING_LEN 126
+#define MAX_USB_STRING_WITH_NULL_LEN (MAX_USB_STRING_LEN+1)
+
static int usb_string_copy(const char *s, char **s_copy)
{
int ret;
char *str;
char *copy = *s_copy;
ret = strlen(s);
- if (ret > 126)
+ if (ret > MAX_USB_STRING_LEN)
return -EOVERFLOW;
- str = kstrdup(s, GFP_KERNEL);
- if (!str)
- return -ENOMEM;
+ if (copy) {
+ str = copy;
+ } else {
+ str = kmalloc(MAX_USB_STRING_WITH_NULL_LEN, GFP_KERNEL);
+ if (!str)
+ return -ENOMEM;
+ }
+ strncpy(str, s, MAX_USB_STRING_WITH_NULL_LEN);
if (str[ret - 1] == '\n')
str[ret - 1] = '\0';
- kfree(copy);
*s_copy = str;
return 0;
}
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile
index 7a64b24b8bf6..a42550950953 100644
--- a/drivers/usb/gadget/function/Makefile
+++ b/drivers/usb/gadget/function/Makefile
@@ -60,7 +60,7 @@ usb_f_cdev-y := f_cdev.o
obj-$(CONFIG_USB_F_CDEV) += usb_f_cdev.o
usb_f_qdss-y := f_qdss.o u_qdss.o
obj-$(CONFIG_USB_F_QDSS) += usb_f_qdss.o
-usb_f_qcrndis-y := f_qc_rndis.o u_data_ipa.o
+usb_f_qcrndis-y := f_qc_rndis.o rndis.o u_data_ipa.o
obj-$(CONFIG_USB_F_QCRNDIS) += usb_f_qcrndis.o
usb_f_rmnet_bam-y := f_rmnet.o u_ctrl_qti.o
obj-$(CONFIG_USB_F_RMNET_BAM) += usb_f_rmnet_bam.o
diff --git a/drivers/usb/gadget/function/f_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c
index db7903d19c43..a2a9185a0143 100644
--- a/drivers/usb/gadget/function/f_audio_source.c
+++ b/drivers/usb/gadget/function/f_audio_source.c
@@ -989,6 +989,7 @@ static ssize_t audio_source_pcm_show(struct device *dev,
struct device *create_function_device(char *name);
+#define AUDIO_SOURCE_DEV_NAME_LENGTH 20
static struct usb_function_instance *audio_source_alloc_inst(void)
{
struct audio_source_instance *fi_audio;
@@ -997,6 +998,8 @@ static struct usb_function_instance *audio_source_alloc_inst(void)
struct device *dev;
void *err_ptr;
int err = 0;
+ char device_name[AUDIO_SOURCE_DEV_NAME_LENGTH];
+ static u8 count;
fi_audio = kzalloc(sizeof(*fi_audio), GFP_KERNEL);
if (!fi_audio)
@@ -1014,7 +1017,11 @@ static struct usb_function_instance *audio_source_alloc_inst(void)
config_group_init_type_name(&fi_audio->func_inst.group, "",
&audio_source_func_type);
- dev = create_function_device("f_audio_source");
+
+ snprintf(device_name, AUDIO_SOURCE_DEV_NAME_LENGTH,
+ "f_audio_source%d", count++);
+
+ dev = create_function_device(device_name);
if (IS_ERR(dev)) {
err_ptr = dev;
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index e309dec68a75..1fd5a95b6e99 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -2336,9 +2336,6 @@ reset:
bh->outreq->complete = bulk_out_complete;
}
- /* prevents usb LPM until thread runs to completion */
- usb_gadget_autopm_get_noresume(common->gadget);
-
common->running = 1;
for (i = 0; i < ARRAY_SIZE(common->luns); ++i)
if (common->luns[i])
@@ -2354,6 +2351,10 @@ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct fsg_dev *fsg = fsg_from_func(f);
fsg->common->new_fsg = fsg;
+
+ /* prevents usb LPM until thread runs to completion */
+ usb_gadget_autopm_get_async(fsg->common->gadget);
+
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
return USB_GADGET_DELAYED_STATUS;
}
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index bf7460f25e61..4a0b3a0aa65e 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -1504,6 +1504,7 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f)
struct usb_request *req;
int i;
+ mtp_string_defs[INTERFACE_STRING_INDEX].id = 0;
mutex_lock(&dev->read_mutex);
while ((req = mtp_req_get(dev, &dev->tx_idle)))
mtp_request_free(req, dev->ep_in);
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index 4e35ed9654b7..2a7d57cd14cb 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -1426,17 +1426,39 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
*/
if (!ncm_opts->bound) {
mutex_lock(&ncm_opts->lock);
+ ncm_opts->net = gether_setup_default();
+ if (IS_ERR(ncm_opts->net)) {
+ status = PTR_ERR(ncm_opts->net);
+ mutex_unlock(&ncm_opts->lock);
+ goto error;
+ }
gether_set_gadget(ncm_opts->net, cdev->gadget);
status = gether_register_netdev(ncm_opts->net);
mutex_unlock(&ncm_opts->lock);
- if (status)
- return status;
+ if (status) {
+ free_netdev(ncm_opts->net);
+ goto error;
+ }
ncm_opts->bound = true;
}
+
+ /* export host's Ethernet address in CDC format */
+ status = gether_get_host_addr_cdc(ncm_opts->net, ncm->ethaddr,
+ sizeof(ncm->ethaddr));
+ if (status < 12) { /* strlen("01234567890a") */
+ ERROR(cdev, "%s: failed to get host eth addr, err %d\n",
+ __func__, status);
+ status = -EINVAL;
+ goto netdev_cleanup;
+ }
+ ncm->port.ioport = netdev_priv(ncm_opts->net);
+
us = usb_gstrings_attach(cdev, ncm_strings,
ARRAY_SIZE(ncm_string_defs));
- if (IS_ERR(us))
- return PTR_ERR(us);
+ if (IS_ERR(us)) {
+ status = PTR_ERR(us);
+ goto netdev_cleanup;
+ }
ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id;
ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id;
ncm_data_intf.iInterface = us[STRING_DATA_IDX].id;
@@ -1540,7 +1562,10 @@ fail:
kfree(ncm->notify_req->buf);
usb_ep_free_request(ncm->notify, ncm->notify_req);
}
+netdev_cleanup:
+ gether_cleanup(netdev_priv(ncm_opts->net));
+error:
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
return status;
@@ -1588,8 +1613,6 @@ static void ncm_free_inst(struct usb_function_instance *f)
opts = container_of(f, struct f_ncm_opts, func_inst);
if (opts->bound)
gether_cleanup(netdev_priv(opts->net));
- else
- free_netdev(opts->net);
kfree(opts);
}
@@ -1602,12 +1625,6 @@ static struct usb_function_instance *ncm_alloc_inst(void)
return ERR_PTR(-ENOMEM);
mutex_init(&opts->lock);
opts->func_inst.free_func_inst = ncm_free_inst;
- opts->net = gether_setup_default();
- if (IS_ERR(opts->net)) {
- struct net_device *net = opts->net;
- kfree(opts);
- return ERR_CAST(net);
- }
config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type);
@@ -1630,6 +1647,8 @@ static void ncm_free(struct usb_function *f)
static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_ncm *ncm = func_to_ncm(f);
+ struct f_ncm_opts *opts = container_of(f->fi, struct f_ncm_opts,
+ func_inst);
DBG(c->cdev, "ncm unbind\n");
@@ -1641,13 +1660,15 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
kfree(ncm->notify_req->buf);
usb_ep_free_request(ncm->notify, ncm->notify_req);
+
+ gether_cleanup(netdev_priv(opts->net));
+ opts->bound = false;
}
static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
{
struct f_ncm *ncm;
struct f_ncm_opts *opts;
- int status;
/* allocate and initialize one new instance */
ncm = kzalloc(sizeof(*ncm), GFP_KERNEL);
@@ -1657,20 +1678,9 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
opts = container_of(fi, struct f_ncm_opts, func_inst);
mutex_lock(&opts->lock);
opts->refcnt++;
-
- /* export host's Ethernet address in CDC format */
- status = gether_get_host_addr_cdc(opts->net, ncm->ethaddr,
- sizeof(ncm->ethaddr));
- if (status < 12) { /* strlen("01234567890a") */
- kfree(ncm);
- mutex_unlock(&opts->lock);
- return ERR_PTR(-EINVAL);
- }
ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr;
-
spin_lock_init(&ncm->lock);
ncm_reset_values(ncm);
- ncm->port.ioport = netdev_priv(opts->net);
mutex_unlock(&opts->lock);
ncm->port.is_fixed = true;
ncm->port.supports_multi_frame = true;
diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c
index 29263a84bbea..88db253aeef4 100644
--- a/drivers/usb/gadget/function/f_qdss.c
+++ b/drivers/usb/gadget/function/f_qdss.c
@@ -493,11 +493,7 @@ static void usb_qdss_disconnect_work(struct work_struct *work)
NULL,
NULL);
- status = set_qdss_data_connection(
- qdss->gadget,
- qdss->port.data,
- qdss->port.data->address,
- 0);
+ status = set_qdss_data_connection(qdss, 0);
if (status)
pr_err("qdss_disconnect error");
}
@@ -543,11 +539,7 @@ static void usb_qdss_connect_work(struct work_struct *work)
}
pr_debug("usb_qdss_connect_work\n");
- status = set_qdss_data_connection(
- qdss->gadget,
- qdss->port.data,
- qdss->port.data->address,
- 1);
+ status = set_qdss_data_connection(qdss, 1);
if (status) {
pr_err("set_qdss_data_connection error(%d)", status);
return;
@@ -868,14 +860,9 @@ void usb_qdss_close(struct usb_qdss_ch *ch)
if (status)
pr_err("%s: uninit_data error\n", __func__);
- status = set_qdss_data_connection(
- gadget,
- qdss->port.data,
- qdss->port.data->address,
- 0);
+ status = set_qdss_data_connection(qdss, 0);
if (status)
pr_err("%s:qdss_disconnect error\n", __func__);
- usb_gadget_restart(gadget);
}
EXPORT_SYMBOL(usb_qdss_close);
diff --git a/drivers/usb/gadget/function/f_qdss.h b/drivers/usb/gadget/function/f_qdss.h
index e3fe8ae03775..cad0f4cc06f9 100644
--- a/drivers/usb/gadget/function/f_qdss.h
+++ b/drivers/usb/gadget/function/f_qdss.h
@@ -1,5 +1,5 @@
/*
- * 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
@@ -69,6 +69,5 @@ struct usb_qdss_opts {
};
int uninit_data(struct usb_ep *ep);
-int set_qdss_data_connection(struct usb_gadget *gadget,
- struct usb_ep *data_ep, u8 data_addr, int enable);
+int set_qdss_data_connection(struct f_qdss *qdss, int enable);
#endif
diff --git a/drivers/usb/gadget/function/u_qdss.c b/drivers/usb/gadget/function/u_qdss.c
index 42a9cda68659..0ef1e2ab34be 100644
--- a/drivers/usb/gadget/function/u_qdss.c
+++ b/drivers/usb/gadget/function/u_qdss.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -40,19 +40,25 @@ static int alloc_sps_req(struct usb_ep *data_ep)
}
static int init_data(struct usb_ep *ep);
-int set_qdss_data_connection(struct usb_gadget *gadget,
- struct usb_ep *data_ep, u8 data_addr, int enable)
+int set_qdss_data_connection(struct f_qdss *qdss, int enable)
{
enum usb_ctrl usb_bam_type;
int res = 0;
int idx;
- struct f_qdss *qdss = data_ep->driver_data;
- struct usb_qdss_bam_connect_info bam_info = qdss->bam_info;
+ struct usb_qdss_bam_connect_info bam_info;
+ struct usb_gadget *gadget;
pr_debug("set_qdss_data_connection\n");
+ if (!qdss) {
+ pr_err("%s: qdss ptr is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ gadget = qdss->gadget;
usb_bam_type = usb_bam_get_bam_type(gadget->name);
+ bam_info = qdss->bam_info;
/* There is only one qdss pipe, so the pipe number can be set to 0 */
idx = usb_bam_get_connection_idx(usb_bam_type, QDSS_P_BAM,
PEER_PERIPHERAL_TO_USB, USB_BAM_DEVICE, 0);
@@ -67,14 +73,16 @@ int set_qdss_data_connection(struct usb_gadget *gadget,
kzalloc(sizeof(struct sps_mem_buffer), GFP_KERNEL);
if (!bam_info.data_fifo) {
pr_err("qdss_data_connection: memory alloc failed\n");
+ usb_bam_free_fifos(usb_bam_type, idx);
return -ENOMEM;
}
get_bam2bam_connection_info(usb_bam_type, idx,
&bam_info.usb_bam_pipe_idx,
NULL, bam_info.data_fifo, NULL);
- alloc_sps_req(data_ep);
- msm_data_fifo_config(data_ep, bam_info.data_fifo->phys_base,
+ alloc_sps_req(qdss->port.data);
+ msm_data_fifo_config(qdss->port.data,
+ bam_info.data_fifo->phys_base,
bam_info.data_fifo->size,
bam_info.usb_bam_pipe_idx);
init_data(qdss->port.data);
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 22d067cd5aa3..6610f7a023d3 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -1033,6 +1033,8 @@ static int dummy_udc_probe(struct platform_device *pdev)
int rc;
dum = *((void **)dev_get_platdata(&pdev->dev));
+ /* Clear usb_gadget region for new registration to udc-core */
+ memzero_explicit(&dum->gadget, sizeof(struct usb_gadget));
dum->gadget.name = gadget_name;
dum->gadget.ops = &dummy_ops;
dum->gadget.max_speed = USB_SPEED_SUPER;
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
index aab5221d6c2e..aac0ce8aeb0b 100644
--- a/drivers/usb/gadget/udc/fsl_udc_core.c
+++ b/drivers/usb/gadget/udc/fsl_udc_core.c
@@ -1249,6 +1249,12 @@ static const struct usb_gadget_ops fsl_gadget_ops = {
.udc_stop = fsl_udc_stop,
};
+/*
+ * Empty complete function used by this driver to fill in the req->complete
+ * field when creating a request since the complete field is mandatory.
+ */
+static void fsl_noop_complete(struct usb_ep *ep, struct usb_request *req) { }
+
/* Set protocol stall on ep0, protocol stall will automatically be cleared
on new transaction */
static void ep0stall(struct fsl_udc *udc)
@@ -1283,7 +1289,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
req->req.length = 0;
req->req.status = -EINPROGRESS;
req->req.actual = 0;
- req->req.complete = NULL;
+ req->req.complete = fsl_noop_complete;
req->dtd_count = 0;
ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
@@ -1366,7 +1372,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
req->req.length = 2;
req->req.status = -EINPROGRESS;
req->req.actual = 0;
- req->req.complete = NULL;
+ req->req.complete = fsl_noop_complete;
req->dtd_count = 0;
ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep));
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index 34388950f96b..a190c97d11e4 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -111,7 +111,7 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci)
xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK);
/* xhci 1.1 controllers have the HCCPARAMS2 register */
- if (hci_version > 100) {
+ if (hci_version > 0x100) {
temp = readl(&xhci->cap_regs->hcc_params2);
xhci_dbg(xhci, "HCC PARAMS2 0x%x:\n", (unsigned int) temp);
xhci_dbg(xhci, " HC %s Force save context capability",
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 3f106b428dba..1ddf882fb607 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -233,9 +233,6 @@ static int xhci_plat_probe(struct platform_device *pdev)
hcd_to_bus(xhci->shared_hcd)->skip_resume = true;
- if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
- xhci->shared_hcd->can_do_streams = 1;
-
hcd->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0);
if (IS_ERR(hcd->usb_phy)) {
ret = PTR_ERR(hcd->usb_phy);
@@ -248,13 +245,16 @@ static int xhci_plat_probe(struct platform_device *pdev)
goto put_usb3_hcd;
}
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_ONESHOT);
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret)
goto disable_usb_phy;
device_wakeup_enable(&hcd->self.root_hub->dev);
- ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED | IRQF_ONESHOT);
+ if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
+ xhci->shared_hcd->can_do_streams = 1;
+
+ ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
if (ret)
goto dealloc_usb2_hcd;
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 82391a0dbc7b..aab1c7903288 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -138,7 +138,13 @@ static int xhci_start(struct xhci_hcd *xhci)
{
u32 temp;
int ret;
+ struct usb_hcd *hcd = xhci_to_hcd(xhci);
+ /*
+ * disable irq to avoid xhci_irq flooding due to unhandeled port
+ * change event in halt state, as soon as xhci_start clears halt bit
+ */
+ disable_irq(hcd->irq);
temp = readl(&xhci->op_regs->command);
temp |= (CMD_RUN);
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Turn on HC, cmd = 0x%x.",
@@ -159,6 +165,8 @@ static int xhci_start(struct xhci_hcd *xhci)
/* clear state flags. Including dying, halted or removing */
xhci->xhc_state = 0;
+ enable_irq(hcd->irq);
+
return ret;
}
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 1950e87b4219..775690bed4c0 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -787,12 +787,6 @@ static int iowarrior_probe(struct usb_interface *interface,
iface_desc = interface->cur_altsetting;
dev->product_id = le16_to_cpu(udev->descriptor.idProduct);
- if (iface_desc->desc.bNumEndpoints < 1) {
- dev_err(&interface->dev, "Invalid number of endpoints\n");
- retval = -EINVAL;
- goto error;
- }
-
/* set up the endpoint information */
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
@@ -803,6 +797,21 @@ static int iowarrior_probe(struct usb_interface *interface,
/* this one will match for the IOWarrior56 only */
dev->int_out_endpoint = endpoint;
}
+
+ if (!dev->int_in_endpoint) {
+ dev_err(&interface->dev, "no interrupt-in endpoint found\n");
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) {
+ if (!dev->int_out_endpoint) {
+ dev_err(&interface->dev, "no interrupt-out endpoint found\n");
+ retval = -ENODEV;
+ goto error;
+ }
+ }
+
/* we have to check the report_size often, so remember it in the endianness suitable for our machine */
dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint);
if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) &&
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index b03d3b867fca..9a9c82a4d35d 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -458,15 +458,11 @@ static int da8xx_musb_exit(struct musb *musb)
}
static const struct musb_platform_ops da8xx_ops = {
- .quirks = MUSB_DMA_CPPI | MUSB_INDEXED_EP,
+ .quirks = MUSB_INDEXED_EP,
.init = da8xx_musb_init,
.exit = da8xx_musb_exit,
.fifo_mode = 2,
-#ifdef CONFIG_USB_TI_CPPI_DMA
- .dma_init = cppi_dma_controller_create,
- .dma_exit = cppi_dma_controller_destroy,
-#endif
.enable = da8xx_musb_enable,
.disable = da8xx_musb_disable,
diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c
index 64916f5566b5..aa11cf2f7417 100644
--- a/drivers/usb/phy/phy-msm-ssusb-qmp.c
+++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -27,10 +27,10 @@
#include <linux/clk/msm-clk.h>
#include <linux/reset.h>
-enum core_ldo_levels {
- CORE_LEVEL_NONE = 0,
- CORE_LEVEL_MIN,
- CORE_LEVEL_MAX,
+enum ldo_levels {
+ VOLTAGE_LEVEL_NONE = 0,
+ VOLTAGE_LEVEL_MIN,
+ VOLTAGE_LEVEL_MAX,
};
#define INIT_MAX_TIME_USEC 1000
@@ -40,6 +40,8 @@ enum core_ldo_levels {
#define USB_SSPHY_1P2_VOL_MAX 1200000 /* uV */
#define USB_SSPHY_HPM_LOAD 23000 /* uA */
+#define USB_SSPHY_LOAD_DEFAULT -1
+
/* USB3PHY_PCIE_USB3_PCS_PCS_STATUS bit */
#define PHYSTATUS BIT(6)
@@ -83,6 +85,9 @@ struct msm_ssphy_qmp {
int vdd_levels[3]; /* none, low, high */
struct regulator *core_ldo;
int core_voltage_levels[3];
+ struct regulator *fpc_redrive_ldo;
+ int redrive_voltage_levels[3];
+ int redrive_load;
struct clk *ref_clk_src;
struct clk *ref_clk;
struct clk *aux_clk;
@@ -162,6 +167,33 @@ static void msm_ssusb_qmp_enable_autonomous(struct msm_ssphy_qmp *phy,
}
}
+static int msm_ldo_enable(struct msm_ssphy_qmp *phy,
+ struct regulator *ldo, int *voltage_levels, int load)
+{
+ int ret = 0;
+
+ dev_dbg(phy->phy.dev,
+ "ldo: min_vol:%duV max_vol:%duV\n",
+ voltage_levels[VOLTAGE_LEVEL_MIN],
+ voltage_levels[VOLTAGE_LEVEL_MAX]);
+
+ if (load > 0) {
+ ret = regulator_set_load(ldo, load);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = regulator_set_voltage(ldo,
+ voltage_levels[VOLTAGE_LEVEL_MIN],
+ voltage_levels[VOLTAGE_LEVEL_MAX]);
+ if (ret)
+ return ret;
+
+ ret = regulator_enable(ldo);
+
+ return ret;
+}
+
static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on)
{
int min, rc = 0;
@@ -181,74 +213,65 @@ static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on)
if (!on)
goto disable_regulators;
- rc = regulator_set_voltage(phy->vdd, phy->vdd_levels[min],
- phy->vdd_levels[2]);
- if (rc) {
- dev_err(phy->phy.dev, "unable to set voltage for ssusb vdd\n");
- return rc;
- }
-
- dev_dbg(phy->phy.dev, "min_vol:%d max_vol:%d\n",
- phy->vdd_levels[min], phy->vdd_levels[2]);
+ if (phy->fpc_redrive_ldo) {
+ rc = msm_ldo_enable(phy, phy->fpc_redrive_ldo,
+ phy->redrive_voltage_levels,
+ phy->redrive_load);
+ if (rc < 0) {
+ dev_err(phy->phy.dev,
+ "enable phy->fpc_redrive_ldo failed\n");
+ return rc;
+ }
- rc = regulator_enable(phy->vdd);
- if (rc) {
- dev_err(phy->phy.dev,
- "regulator_enable(phy->vdd) failed, ret=%d",
- rc);
- goto unconfig_vdd;
+ dev_dbg(phy->phy.dev,
+ "fpc redrive ldo: min_vol:%duV max_vol:%duV\n",
+ phy->redrive_voltage_levels[VOLTAGE_LEVEL_MIN],
+ phy->redrive_voltage_levels[VOLTAGE_LEVEL_MAX]);
}
- rc = regulator_set_load(phy->core_ldo, USB_SSPHY_HPM_LOAD);
+ rc = msm_ldo_enable(phy, phy->vdd, phy->vdd_levels,
+ USB_SSPHY_LOAD_DEFAULT);
if (rc < 0) {
- dev_err(phy->phy.dev, "Unable to set HPM of core_ldo\n");
- goto disable_vdd;
+ dev_err(phy->phy.dev, "enable phy->vdd failed\n");
+ goto disable_fpc_redrive;
}
- rc = regulator_set_voltage(phy->core_ldo,
- phy->core_voltage_levels[CORE_LEVEL_MIN],
- phy->core_voltage_levels[CORE_LEVEL_MAX]);
- if (rc) {
- dev_err(phy->phy.dev, "unable to set voltage for core_ldo\n");
- goto put_core_ldo_lpm;
- }
+ dev_dbg(phy->phy.dev,
+ "vdd ldo: min_vol:%duV max_vol:%duV\n",
+ phy->vdd_levels[VOLTAGE_LEVEL_MIN],
+ phy->vdd_levels[VOLTAGE_LEVEL_MAX]);
- rc = regulator_enable(phy->core_ldo);
- if (rc) {
- dev_err(phy->phy.dev, "Unable to enable core_ldo\n");
- goto unset_core_ldo;
+ rc = msm_ldo_enable(phy, phy->core_ldo, phy->core_voltage_levels,
+ USB_SSPHY_HPM_LOAD);
+ if (rc < 0) {
+ dev_err(phy->phy.dev, "enable phy->core_ldo failed\n");
+ goto disable_vdd;
}
+ dev_dbg(phy->phy.dev,
+ "core ldo: min_vol:%duV max_vol:%duV\n",
+ phy->core_voltage_levels[VOLTAGE_LEVEL_MIN],
+ phy->core_voltage_levels[VOLTAGE_LEVEL_MAX]);
+
return 0;
disable_regulators:
rc = regulator_disable(phy->core_ldo);
if (rc)
- dev_err(phy->phy.dev, "Unable to disable core_ldo\n");
-
-unset_core_ldo:
- rc = regulator_set_voltage(phy->core_ldo,
- phy->core_voltage_levels[CORE_LEVEL_NONE],
- phy->core_voltage_levels[CORE_LEVEL_MAX]);
- if (rc)
- dev_err(phy->phy.dev, "unable to set voltage for core_ldo\n");
-
-put_core_ldo_lpm:
- rc = regulator_set_load(phy->core_ldo, 0);
- if (rc < 0)
- dev_err(phy->phy.dev, "Unable to set LPM of core_ldo\n");
+ dev_err(phy->phy.dev, "disable phy->core_ldo failed\n");
disable_vdd:
rc = regulator_disable(phy->vdd);
if (rc)
- dev_err(phy->phy.dev, "regulator_disable(phy->vdd) failed, ret=%d",
- rc);
+ dev_err(phy->phy.dev, "disable phy->vdd failed\n");
-unconfig_vdd:
- rc = regulator_set_voltage(phy->vdd, phy->vdd_levels[min],
- phy->vdd_levels[2]);
- if (rc)
- dev_err(phy->phy.dev, "unable to set voltage for ssusb vdd\n");
+disable_fpc_redrive:
+ if (phy->fpc_redrive_ldo) {
+ rc = regulator_disable(phy->fpc_redrive_ldo);
+ if (rc)
+ dev_err(phy->phy.dev,
+ "disable phy->fpc_redrive_ldo failed\n");
+ }
return rc < 0 ? rc : 0;
}
@@ -307,10 +330,6 @@ static int msm_ssphy_qmp_init(struct usb_phy *uphy)
phy->clk_enabled = true;
}
- /* select usb3 phy mode */
- if (phy->tcsr_usb3_dp_phymode)
- writel_relaxed(0x0, phy->tcsr_usb3_dp_phymode);
-
writel_relaxed(0x01,
phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]);
@@ -386,6 +405,10 @@ static int msm_ssphy_qmp_reset(struct usb_phy *uphy)
goto deassert_phy_phy_reset;
}
+ /* select usb3 phy mode */
+ if (phy->tcsr_usb3_dp_phymode)
+ writel_relaxed(0x0, phy->tcsr_usb3_dp_phymode);
+
/* Deassert USB3 PHY CSR reset */
ret = reset_control_deassert(phy->phy_reset);
if (ret) {
@@ -683,9 +706,9 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev)
}
/* Set default core voltage values */
- phy->core_voltage_levels[CORE_LEVEL_NONE] = 0;
- phy->core_voltage_levels[CORE_LEVEL_MIN] = USB_SSPHY_1P2_VOL_MIN;
- phy->core_voltage_levels[CORE_LEVEL_MAX] = USB_SSPHY_1P2_VOL_MAX;
+ phy->core_voltage_levels[VOLTAGE_LEVEL_NONE] = 0;
+ phy->core_voltage_levels[VOLTAGE_LEVEL_MIN] = USB_SSPHY_1P2_VOL_MIN;
+ phy->core_voltage_levels[VOLTAGE_LEVEL_MAX] = USB_SSPHY_1P2_VOL_MAX;
if (of_get_property(dev->of_node, "qcom,core-voltage-level", &len) &&
len == sizeof(phy->core_voltage_levels)) {
@@ -729,6 +752,39 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev)
goto err;
}
+ phy->fpc_redrive_ldo = devm_regulator_get_optional(dev, "fpc-redrive");
+ if (IS_ERR(phy->fpc_redrive_ldo)) {
+ phy->fpc_redrive_ldo = NULL;
+ dev_dbg(dev, "no FPC re-drive ldo regulator\n");
+ } else {
+ if (of_get_property(dev->of_node,
+ "qcom,redrive-voltage-level", &len) &&
+ len == sizeof(phy->redrive_voltage_levels)) {
+ ret = of_property_read_u32_array(dev->of_node,
+ "qcom,redrive-voltage-level",
+ (u32 *) phy->redrive_voltage_levels,
+ len / sizeof(u32));
+ if (ret) {
+ dev_err(dev,
+ "err qcom,redrive-voltage-level\n");
+ goto err;
+ }
+ } else {
+ ret = -EINVAL;
+ dev_err(dev, "err inputs for redrive-voltage-level\n");
+ goto err;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "qcom,redrive-load",
+ &phy->redrive_load);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to read redrive load\n");
+ goto err;
+ }
+
+ dev_dbg(dev, "Get FPC re-drive ldo regulator\n");
+ }
+
phy->ref_clk_src = devm_clk_get(dev, "ref_clk_src");
if (IS_ERR(phy->ref_clk_src))
phy->ref_clk_src = NULL;
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 1532cde8a437..7812052dc700 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -99,10 +99,17 @@ static int ark3116_read_reg(struct usb_serial *serial,
usb_rcvctrlpipe(serial->dev, 0),
0xfe, 0xc0, 0, reg,
buf, 1, ARK_TIMEOUT);
- if (result < 0)
+ if (result < 1) {
+ dev_err(&serial->interface->dev,
+ "failed to read register %u: %d\n",
+ reg, result);
+ if (result >= 0)
+ result = -EIO;
+
return result;
- else
- return buf[0];
+ }
+
+ return buf[0];
}
static inline int calc_divisor(int bps)
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index fe7452f0f38a..33cec50978b8 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -171,6 +171,8 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */
{ USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */
{ USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */
+ { USB_DEVICE(0x1901, 0x0195) }, /* GE B850/B650/B450 CP2104 DP UART interface */
+ { USB_DEVICE(0x1901, 0x0196) }, /* GE B850 CP2105 DP UART interface */
{ USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */
{ USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */
{ USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 3df7b7ec178e..e0b1fe2f60e1 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -1483,16 +1483,20 @@ static int digi_read_oob_callback(struct urb *urb)
struct usb_serial *serial = port->serial;
struct tty_struct *tty;
struct digi_port *priv = usb_get_serial_port_data(port);
+ unsigned char *buf = urb->transfer_buffer;
int opcode, line, status, val;
int i;
unsigned int rts;
+ if (urb->actual_length < 4)
+ return -1;
+
/* handle each oob command */
- for (i = 0; i < urb->actual_length - 3;) {
- opcode = ((unsigned char *)urb->transfer_buffer)[i++];
- line = ((unsigned char *)urb->transfer_buffer)[i++];
- status = ((unsigned char *)urb->transfer_buffer)[i++];
- val = ((unsigned char *)urb->transfer_buffer)[i++];
+ for (i = 0; i < urb->actual_length - 3; i += 4) {
+ opcode = buf[i];
+ line = buf[i + 1];
+ status = buf[i + 2];
+ val = buf[i + 3];
dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n",
opcode, line, status, val);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index d3d6ec455151..19a98116c2ab 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1807,8 +1807,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
mutex_init(&priv->cfg_lock);
- priv->flags = ASYNC_LOW_LATENCY;
-
if (quirk && quirk->port_probe)
quirk->port_probe(priv);
@@ -2072,6 +2070,20 @@ static int ftdi_process_packet(struct usb_serial_port *port,
priv->prev_status = status;
}
+ /* save if the transmitter is empty or not */
+ if (packet[1] & FTDI_RS_TEMT)
+ priv->transmit_empty = 1;
+ else
+ priv->transmit_empty = 0;
+
+ len -= 2;
+ if (!len)
+ return 0; /* status only */
+
+ /*
+ * Break and error status must only be processed for packets with
+ * data payload to avoid over-reporting.
+ */
flag = TTY_NORMAL;
if (packet[1] & FTDI_RS_ERR_MASK) {
/* Break takes precedence over parity, which takes precedence
@@ -2094,15 +2106,6 @@ static int ftdi_process_packet(struct usb_serial_port *port,
}
}
- /* save if the transmitter is empty or not */
- if (packet[1] & FTDI_RS_TEMT)
- priv->transmit_empty = 1;
- else
- priv->transmit_empty = 0;
-
- len -= 2;
- if (!len)
- return 0; /* status only */
port->icount.rx += len;
ch = packet + 2;
@@ -2433,8 +2436,12 @@ static int ftdi_get_modem_status(struct usb_serial_port *port,
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
0, priv->interface,
buf, len, WDR_TIMEOUT);
- if (ret < 0) {
+
+ /* NOTE: We allow short responses and handle that below. */
+ if (ret < 1) {
dev_err(&port->dev, "failed to get modem status: %d\n", ret);
+ if (ret >= 0)
+ ret = -EIO;
ret = usb_translate_errors(ret);
goto out;
}
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index c02808a30436..f1a8fdcd8674 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -1674,6 +1674,12 @@ static void edge_interrupt_callback(struct urb *urb)
function = TIUMP_GET_FUNC_FROM_CODE(data[0]);
dev_dbg(dev, "%s - port_number %d, function %d, info 0x%x\n", __func__,
port_number, function, data[1]);
+
+ if (port_number >= edge_serial->serial->num_ports) {
+ dev_err(dev, "bad port number %d\n", port_number);
+ goto exit;
+ }
+
port = edge_serial->serial->port[port_number];
edge_port = usb_get_serial_port_data(port);
if (!edge_port) {
@@ -1755,7 +1761,7 @@ static void edge_bulk_in_callback(struct urb *urb)
port_number = edge_port->port->port_number;
- if (edge_port->lsr_event) {
+ if (urb->actual_length > 0 && edge_port->lsr_event) {
edge_port->lsr_event = 0;
dev_dbg(dev, "%s ===== Port %u LSR Status = %02x, Data = %02x ======\n",
__func__, port_number, edge_port->lsr_mask, *data);
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 97ea52b5cfd4..d17685cc00c9 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1024,6 +1024,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
* (can't set it up in mos7840_startup as the structures *
* were not set up at that time.) */
if (port0->open_ports == 1) {
+ /* FIXME: Buffer never NULL, so URB is not submitted. */
if (serial->port[0]->interrupt_in_buffer == NULL) {
/* set up interrupt urb */
usb_fill_int_urb(serial->port[0]->interrupt_in_urb,
@@ -2119,7 +2120,8 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
static int mos7840_attach(struct usb_serial *serial)
{
if (serial->num_bulk_in < serial->num_ports ||
- serial->num_bulk_out < serial->num_ports) {
+ serial->num_bulk_out < serial->num_ports ||
+ serial->num_interrupt_in < 1) {
dev_err(&serial->interface->dev, "missing endpoints\n");
return -ENODEV;
}
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index a180b17d2432..76564b3bebb9 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -142,12 +142,6 @@ static int omninet_port_remove(struct usb_serial_port *port)
static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
- struct usb_serial_port *wport;
-
- wport = serial->port[1];
- tty_port_tty_set(&wport->port, tty);
-
return usb_serial_generic_open(tty, port);
}
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index 4b7bfb394a32..64bf258e7e00 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -142,7 +142,7 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_clear_halt(port->serial->dev, port->read_urb->pipe);
res = usb_serial_generic_open(tty, port);
- if (!res)
+ if (res)
return res;
/* Request CTS line state, sometimes during opening the current
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index b2dff0f14743..236ea43f7815 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -205,6 +205,11 @@ static void safe_process_read_urb(struct urb *urb)
if (!safe)
goto out;
+ if (length < 2) {
+ dev_err(&port->dev, "malformed packet\n");
+ return;
+ }
+
fcs = fcs_compute10(data, length, CRC10_INITFCS);
if (fcs) {
dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs);
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index 475e6c31b266..ddfd787c461c 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -232,11 +232,17 @@ static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status)
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
GET_UART_STATUS, GET_UART_STATUS_TYPE,
0, GET_UART_STATUS_MSR, buf, 1, 100);
- if (ret < 0)
+ if (ret < 1) {
dev_err(&port->dev, "failed to get modem status: %d\n", ret);
+ if (ret >= 0)
+ ret = -EIO;
+ goto out;
+ }
dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x\n", ret, *buf);
*status = *buf;
+ ret = 0;
+out:
kfree(buf);
return ret;
diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c
index 101aa508b8f0..2d499ef903d3 100644
--- a/drivers/video/fbdev/msm/mdss_dp.c
+++ b/drivers/video/fbdev/msm/mdss_dp.c
@@ -1013,9 +1013,10 @@ static int dp_get_cable_status(struct platform_device *pdev, u32 vote)
return hpd;
}
-static bool mdss_dp_is_dvi_mode(struct mdss_dp_drv_pdata *dp)
+static bool mdss_dp_sink_audio_supp(struct mdss_dp_drv_pdata *dp)
{
- return hdmi_edid_is_dvi_mode(dp->panel_data.panel_info.edid_data);
+ return hdmi_edid_is_audio_supported(
+ dp->panel_data.panel_info.edid_data);
}
static int dp_audio_info_setup(struct platform_device *pdev,
@@ -1576,8 +1577,14 @@ int mdss_dp_on_hpd(struct mdss_dp_drv_pdata *dp_drv)
link_training:
dp_drv->power_on = true;
- while (-EAGAIN == mdss_dp_setup_main_link(dp_drv, true))
+ while (-EAGAIN == mdss_dp_setup_main_link(dp_drv, true)) {
pr_debug("MAIN LINK TRAINING RETRY\n");
+ mdss_dp_mainlink_ctrl(&dp_drv->ctrl_io, false);
+ /* Disable DP mainlink clocks */
+ mdss_dp_disable_mainlink_clocks(dp_drv);
+ /* Enable DP mainlink clocks with reduced link rate */
+ mdss_dp_enable_mainlink_clocks(dp_drv);
+ }
dp_drv->cont_splash = 0;
@@ -1706,14 +1713,17 @@ static int mdss_dp_send_audio_notification(
goto end;
}
- if (!mdss_dp_is_dvi_mode(dp) || dp->audio_test_req) {
+ if (mdss_dp_sink_audio_supp(dp) || dp->audio_test_req) {
dp->audio_test_req = false;
+ pr_debug("sending audio notification\n");
flags |= MSM_EXT_DISP_HPD_AUDIO;
if (dp->ext_audio_data.intf_ops.hpd)
ret = dp->ext_audio_data.intf_ops.hpd(dp->ext_pdev,
dp->ext_audio_data.type, val, flags);
+ } else {
+ pr_debug("sink does not support audio\n");
}
end:
@@ -1789,8 +1799,6 @@ static int mdss_dp_edid_init(struct mdss_panel_data *pdata)
dp_drv->edid_buf = edid_init_data.buf;
dp_drv->edid_buf_size = edid_init_data.buf_size;
- mdss_dp_set_default_resolution(dp_drv);
-
return 0;
}
@@ -2005,14 +2013,21 @@ static int mdss_dp_process_hpd_high(struct mdss_dp_drv_pdata *dp)
pr_debug("start\n");
- mdss_dp_dpcd_cap_read(dp);
+ ret = mdss_dp_dpcd_cap_read(dp);
+ if (ret || !mdss_dp_aux_is_link_rate_valid(dp->dpcd.max_link_rate) ||
+ !mdss_dp_aux_is_lane_count_valid(dp->dpcd.max_lane_count)) {
+ /*
+ * If there is an error in parsing DPCD or if DPCD reports
+ * unsupported link parameters then set the default link
+ * parameters and continue to read EDID.
+ */
+ pr_err("dpcd read failed, set failsafe parameters\n");
+ mdss_dp_set_default_link_parameters(dp);
+ }
ret = mdss_dp_edid_read(dp);
if (ret) {
- pr_debug("edid read error, setting default resolution\n");
-
- mdss_dp_set_default_resolution(dp);
- mdss_dp_set_default_link_parameters(dp);
+ pr_err("edid read error, setting default resolution\n");
goto notify;
}
@@ -2023,15 +2038,19 @@ static int mdss_dp_process_hpd_high(struct mdss_dp_drv_pdata *dp)
ret = hdmi_edid_parser(dp->panel_data.panel_info.edid_data);
if (ret) {
pr_err("edid parse failed, setting default resolution\n");
-
- mdss_dp_set_default_resolution(dp);
- mdss_dp_set_default_link_parameters(dp);
goto notify;
}
dp->sink_info_read = true;
notify:
+ if (ret) {
+ /* set failsafe parameters */
+ pr_info("falling back to failsafe mode\n");
+ mdss_dp_set_default_resolution(dp);
+ mdss_dp_set_default_link_parameters(dp);
+ }
+
/* Check if there is a PHY_TEST_PATTERN request when we get HPD high.
* Update the DP driver with the test parameters including link rate,
* lane count, voltage level, and pre-emphasis level. Do not notify
diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h
index 34b652d843aa..4decb26ea073 100644
--- a/drivers/video/fbdev/msm/mdss_dp.h
+++ b/drivers/video/fbdev/msm/mdss_dp.h
@@ -1038,7 +1038,7 @@ static inline void mdss_dp_reset_frame_crc_data(struct mdss_dp_crc_data *crc)
void mdss_dp_phy_initialize(struct mdss_dp_drv_pdata *dp);
-void mdss_dp_dpcd_cap_read(struct mdss_dp_drv_pdata *dp);
+int mdss_dp_dpcd_cap_read(struct mdss_dp_drv_pdata *dp);
int mdss_dp_dpcd_status_read(struct mdss_dp_drv_pdata *dp);
void mdss_dp_aux_parse_sink_status_field(struct mdss_dp_drv_pdata *dp);
int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp);
diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c
index 479c367fdc92..8566b1d6985a 100644
--- a/drivers/video/fbdev/msm/mdss_dp_aux.c
+++ b/drivers/video/fbdev/msm/mdss_dp_aux.c
@@ -826,9 +826,9 @@ int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp)
return ret;
}
-static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep,
- int len)
+int mdss_dp_dpcd_cap_read(struct mdss_dp_drv_pdata *ep)
{
+ int const len = 16; /* read 16 bytes */
char *bp;
char data;
struct dpcd_cap *cap;
@@ -838,8 +838,15 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep,
rlen = dp_aux_read_buf(ep, 0, len, 0);
if (rlen <= 0) {
pr_err("edp aux read failed\n");
- return;
+ return rlen;
+ }
+
+ if (rlen != len) {
+ pr_debug("Read size expected(%d) bytes, actual(%d) bytes\n",
+ len, rlen);
+ return -EINVAL;
}
+
rp = &ep->rxp;
cap = &ep->dpcd;
bp = rp->data;
@@ -849,15 +856,11 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep,
data = *bp++; /* byte 0 */
cap->major = (data >> 4) & 0x0f;
cap->minor = data & 0x0f;
- if (--rlen <= 0)
- return;
pr_debug("version: %d.%d\n", cap->major, cap->minor);
data = *bp++; /* byte 1 */
/* 162, 270 and 540 MB, symbol rate, NOT bit rate */
cap->max_link_rate = data;
- if (--rlen <= 0)
- return;
pr_debug("link_rate=%d\n", cap->max_link_rate);
data = *bp++; /* byte 2 */
@@ -873,8 +876,6 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep,
data &= 0x0f;
cap->max_lane_count = data;
- if (--rlen <= 0)
- return;
pr_debug("lane_count=%d\n", cap->max_lane_count);
data = *bp++; /* byte 3 */
@@ -887,14 +888,10 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep,
cap->flags |= DPCD_NO_AUX_HANDSHAKE;
pr_debug("NO Link Training\n");
}
- if (--rlen <= 0)
- return;
data = *bp++; /* byte 4 */
cap->num_rx_port = (data & BIT(0)) + 1;
pr_debug("rx_ports=%d", cap->num_rx_port);
- if (--rlen <= 0)
- return;
data = *bp++; /* Byte 5: DOWN_STREAM_PORT_PRESENT */
cap->downstream_port.dfp_present = data & BIT(0);
@@ -907,13 +904,8 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep,
pr_debug("format_conversion = %d, detailed_cap_info_available = %d\n",
cap->downstream_port.format_conversion,
cap->downstream_port.detailed_cap_info_available);
- if (--rlen <= 0)
- return;
bp += 1; /* Skip Byte 6 */
- rlen -= 1;
- if (rlen <= 0)
- return;
data = *bp++; /* Byte 7: DOWN_STREAM_PORT_COUNT */
cap->downstream_port.dfp_count = data & 0x7;
@@ -923,34 +915,23 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep,
cap->downstream_port.dfp_count,
cap->downstream_port.msa_timing_par_ignored);
pr_debug("oui_support = %d\n", cap->downstream_port.oui_support);
- if (--rlen <= 0)
- return;
data = *bp++; /* byte 8 */
if (data & BIT(1)) {
cap->flags |= DPCD_PORT_0_EDID_PRESENTED;
pr_debug("edid presented\n");
}
- if (--rlen <= 0)
- return;
data = *bp++; /* byte 9 */
cap->rx_port0_buf_size = (data + 1) * 32;
pr_debug("lane_buf_size=%d\n", cap->rx_port0_buf_size);
- if (--rlen <= 0)
- return;
bp += 2; /* skip 10, 11 port1 capability */
- rlen -= 2;
- if (rlen <= 0)
- return;
data = *bp++; /* byte 12 */
cap->i2c_speed_ctrl = data;
if (cap->i2c_speed_ctrl > 0)
pr_debug("i2c_rate=%d", cap->i2c_speed_ctrl);
- if (--rlen <= 0)
- return;
data = *bp++; /* byte 13 */
cap->scrambler_reset = data & BIT(0);
@@ -962,8 +943,6 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep,
pr_debug("enhanced_framing=%d\n",
cap->enhanced_frame);
- if (--rlen <= 0)
- return;
data = *bp++; /* byte 14 */
if (data == 0)
@@ -974,6 +953,8 @@ static void dp_sink_capability_read(struct mdss_dp_drv_pdata *ep,
cap->training_read_interval);
dp_sink_parse_sink_count(ep);
+
+ return 0;
}
int mdss_dp_aux_link_status_read(struct mdss_dp_drv_pdata *ep, int len)
@@ -2379,11 +2360,6 @@ clear:
return ret;
}
-void mdss_dp_dpcd_cap_read(struct mdss_dp_drv_pdata *ep)
-{
- dp_sink_capability_read(ep, 16);
-}
-
void mdss_dp_aux_parse_sink_status_field(struct mdss_dp_drv_pdata *ep)
{
dp_sink_parse_sink_count(ep);
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index b1944a9a6323..17722eac3006 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -1463,15 +1463,6 @@ int mdss_dsi_on(struct mdss_panel_data *pdata)
if (mipi->init_delay)
usleep_range(mipi->init_delay, mipi->init_delay);
- if (mipi->force_clk_lane_hs) {
- u32 tmp;
-
- tmp = MIPI_INP((ctrl_pdata->ctrl_base) + 0xac);
- tmp |= (1<<28);
- MIPI_OUTP((ctrl_pdata->ctrl_base) + 0xac, tmp);
- wmb();
- }
-
if (pdata->panel_info.type == MIPI_CMD_PANEL)
mdss_dsi_clk_ctrl(ctrl_pdata, ctrl_pdata->dsi_clk_handle,
MDSS_DSI_ALL_CLKS, MDSS_DSI_CLK_OFF);
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index 66c0cb029720..2a76466abf3e 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -699,6 +699,8 @@ void mdss_dsi_dsc_config(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsc_desc *dsc);
void mdss_dsi_dfps_config_8996(struct mdss_dsi_ctrl_pdata *ctrl);
void mdss_dsi_set_burst_mode(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_cfg_lane_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
+ u32 bits, int set);
void mdss_dsi_set_reg(struct mdss_dsi_ctrl_pdata *ctrl, int off,
u32 mask, u32 val);
int mdss_dsi_phy_pll_reset_status(struct mdss_dsi_ctrl_pdata *ctrl);
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index 982e7a02ffa3..9f4b7eb52492 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -602,7 +602,7 @@ error:
return rc;
}
-static void mdss_dsi_cfg_lane_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
+void mdss_dsi_cfg_lane_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
u32 bits, int set)
{
u32 data;
@@ -613,6 +613,7 @@ static void mdss_dsi_cfg_lane_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
else
data &= ~bits;
MIPI_OUTP(ctrl->ctrl_base + 0x0ac, data);
+ wmb(); /* make sure write happens */
}
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index bf701e2a4ac5..6f20c0ed0455 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -365,13 +365,17 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
if (gpio_is_valid(ctrl_pdata->bklt_en_gpio)) {
- if (ctrl_pdata->bklt_en_gpio_invert)
+ if (ctrl_pdata->bklt_en_gpio_invert) {
rc = gpio_direction_output(
ctrl_pdata->bklt_en_gpio, 0);
- else
+ gpio_set_value(
+ (ctrl_pdata->bklt_en_gpio), 0);
+ } else {
rc = gpio_direction_output(
ctrl_pdata->bklt_en_gpio, 1);
-
+ gpio_set_value(
+ (ctrl_pdata->bklt_en_gpio), 1);
+ }
if (rc) {
pr_err("%s: unable to set dir for bklt gpio\n",
__func__);
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index bf66c0cd430c..fc47de7692e7 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -301,6 +301,7 @@ static void mdss_fb_set_bl_brightness(struct led_classdev *led_cdev,
mdss_fb_set_backlight(mfd, bl_lvl);
mutex_unlock(&mfd->bl_lock);
}
+ mfd->bl_level_usr = bl_lvl;
}
static enum led_brightness mdss_fb_get_bl_brightness(
@@ -309,7 +310,7 @@ static enum led_brightness mdss_fb_get_bl_brightness(
struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
enum led_brightness value;
- MDSS_BL_TO_BRIGHT(value, mfd->bl_level, mfd->panel_info->bl_max,
+ MDSS_BL_TO_BRIGHT(value, mfd->bl_level_usr, mfd->panel_info->bl_max,
mfd->panel_info->brightness_max);
return value;
@@ -1275,6 +1276,8 @@ static int mdss_fb_probe(struct platform_device *pdev)
mfd->fb_imgType = MDP_RGBA_8888;
mfd->calib_mode_bl = 0;
mfd->unset_bl_level = U32_MAX;
+ mfd->bl_extn_level = -1;
+ mfd->bl_level_usr = backlight_led.brightness;
mfd->pdev = pdev;
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index 321531c72a08..f046ff08cbf7 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -314,6 +314,7 @@ struct msm_fb_data_type {
u32 unset_bl_level;
bool allow_bl_update;
u32 bl_level_scaled;
+ u32 bl_level_usr;
struct mutex bl_lock;
struct mutex mdss_sysfs_lock;
bool ipc_resume;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
index 6bf8e581326d..37c4be6135aa 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
@@ -137,6 +137,7 @@ struct hdmi_edid_ctrl {
u16 video_latency;
u32 present_3d;
u32 page_id;
+ bool basic_audio_supp;
u8 audio_data_block[MAX_NUMBER_ADB * MAX_AUDIO_DATA_BLOCK_SIZE];
int adb_size;
u8 spkr_alloc_data_block[MAX_SPKR_ALLOC_DATA_BLOCK_SIZE];
@@ -1289,6 +1290,14 @@ static void hdmi_edid_extract_sink_caps(struct hdmi_edid_ctrl *edid_ctrl,
return;
}
+ /* Check if sink supports basic audio */
+ if (in_buf[3] & BIT(6))
+ edid_ctrl->basic_audio_supp = true;
+ else
+ edid_ctrl->basic_audio_supp = false;
+ pr_debug("%s: basic audio supported: %s\n", __func__,
+ edid_ctrl->basic_audio_supp ? "true" : "false");
+
vsd = hdmi_edid_find_hfvsdb(in_buf);
if (vsd) {
@@ -1501,6 +1510,17 @@ static void hdmi_edid_detail_desc(struct hdmi_edid_ctrl *edid_ctrl,
*/
active_h = ((((u32)data_buf[0x4] >> 0x4) & 0xF) << 8)
| data_buf[0x2];
+ /*
+ * It is possible that a sink might try to fit in the resolution
+ * which has an active_h of 4096 into a DTD. However, DTD has only
+ * 12 bit to represent active_h which would limit the maximum value
+ * to 4095. If such a case is detected, set the active_h explicitly
+ * to 4096.
+ */
+ if (active_h == 0xFFF) {
+ pr_debug("overriding h_active to 4096\n");
+ active_h++;
+ }
/*
* EDID_TIMING_DESC_H_BLANK[0x3]: Relative Offset to the EDID detailed
@@ -2627,6 +2647,17 @@ void hdmi_edid_set_max_pclk_rate(void *input, u32 max_pclk_khz)
edid_ctrl->init_data.max_pclk_khz = max_pclk_khz;
}
+bool hdmi_edid_is_audio_supported(void *input)
+{
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+ /*
+ * return true if basic audio is supported or if an audio
+ * data block was successfully parsed.
+ */
+ return (edid_ctrl->basic_audio_supp || edid_ctrl->adb_size);
+}
+
void hdmi_edid_deinit(void *input)
{
struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
index 653276683981..557e9326a81d 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
@@ -80,5 +80,6 @@ void hdmi_edid_get_hdr_data(void *edid_ctrl,
void hdmi_edid_config_override(void *input, bool enable,
struct hdmi_edid_override_data *data);
void hdmi_edid_set_max_pclk_rate(void *input, u32 max_pclk_khz);
+bool hdmi_edid_is_audio_supported(void *input);
#endif /* __HDMI_EDID_H__ */
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index f05d4cb2922a..42845f9ff192 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -380,6 +380,13 @@ static inline u32 hdmi_tx_is_dvi_mode(struct hdmi_tx_ctrl *hdmi_ctrl)
return hdmi_edid_is_dvi_mode(hdmi_tx_get_fd(HDMI_TX_FEAT_EDID));
} /* hdmi_tx_is_dvi_mode */
+static inline u32 hdmi_tx_is_in_splash(struct hdmi_tx_ctrl *hdmi_ctrl)
+{
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
+
+ return mdata->handoff_pending;
+}
+
static inline bool hdmi_tx_is_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl)
{
return hdmi_ctrl->hpd_state && hdmi_ctrl->panel_power_on;
@@ -416,15 +423,27 @@ static inline void hdmi_tx_cec_device_suspend(struct hdmi_tx_ctrl *hdmi_ctrl)
}
static inline void hdmi_tx_send_cable_notification(
- struct hdmi_tx_ctrl *hdmi_ctrl, int val)
+ struct hdmi_tx_ctrl *hdmi_ctrl, int val, bool async)
{
if (hdmi_ctrl && hdmi_ctrl->ext_audio_data.intf_ops.hpd) {
u32 flags = 0;
- flags |= MSM_EXT_DISP_HPD_VIDEO;
+ if (async || hdmi_tx_is_in_splash(hdmi_ctrl)) {
+ flags |= MSM_EXT_DISP_HPD_ASYNC_VIDEO;
- if (!hdmi_tx_is_dvi_mode(hdmi_ctrl))
- flags |= MSM_EXT_DISP_HPD_AUDIO;
+ if (async) {
+ if (!hdmi_tx_is_dvi_mode(hdmi_ctrl))
+ flags |= MSM_EXT_DISP_HPD_ASYNC_AUDIO;
+ } else
+ if (!hdmi_tx_is_dvi_mode(hdmi_ctrl))
+ flags |= MSM_EXT_DISP_HPD_AUDIO;
+
+ } else {
+ flags |= MSM_EXT_DISP_HPD_VIDEO;
+
+ if (!hdmi_tx_is_dvi_mode(hdmi_ctrl))
+ flags |= MSM_EXT_DISP_HPD_AUDIO;
+ }
hdmi_ctrl->ext_audio_data.intf_ops.hpd(hdmi_ctrl->ext_pdev,
hdmi_ctrl->ext_audio_data.type, val, flags);
@@ -859,7 +878,11 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev,
hdmi_tx_config_5v(hdmi_ctrl, false);
} else {
hdmi_tx_hpd_off(hdmi_ctrl);
- hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
+ /*
+ * No need to blocking wait for display/audio in this
+ * case since HAL is not up so no ACK can be expected.
+ */
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 0, true);
}
break;
@@ -2339,7 +2362,7 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work)
mutex_unlock(&hdmi_ctrl->tx_lock);
- hdmi_tx_send_cable_notification(hdmi_ctrl, hdmi_ctrl->hpd_state);
+ hdmi_tx_send_cable_notification(hdmi_ctrl, hdmi_ctrl->hpd_state, false);
} /* hdmi_tx_hpd_int_work */
static int hdmi_tx_check_capability(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -3956,7 +3979,7 @@ static int hdmi_tx_post_evt_handle_resume(struct hdmi_tx_ctrl *hdmi_ctrl)
&hdmi_ctrl->hpd_int_done, HZ/10);
if (!timeout) {
pr_debug("cable removed during suspend\n");
- hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 0, false);
}
}
@@ -3967,7 +3990,7 @@ static int hdmi_tx_post_evt_handle_panel_on(struct hdmi_tx_ctrl *hdmi_ctrl)
{
if (hdmi_ctrl->panel_suspend) {
pr_debug("panel suspend has triggered\n");
- hdmi_tx_send_cable_notification(hdmi_ctrl, 0);
+ hdmi_tx_send_cable_notification(hdmi_ctrl, 0, false);
}
return 0;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index b09e771c4ea6..171f44815430 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -2179,6 +2179,8 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
mdss_set_quirk(mdata, MDSS_QUIRK_HDR_SUPPORT_ENABLED);
break;
case MDSS_MDP_HW_REV_320:
+ mdss_set_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU);
+ mdss_set_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT);
case MDSS_MDP_HW_REV_330:
mdata->max_target_zorder = 7; /* excluding base layer */
mdata->max_cursor_size = 512;
@@ -2218,8 +2220,6 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata)
set_bit(MDSS_CAPS_MDP_VOTE_CLK_NOT_SUPPORTED,
mdata->mdss_caps_map);
mdss_mdp_init_default_prefill_factors(mdata);
- mdss_set_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU);
- mdss_set_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT);
mdss_set_quirk(mdata, MDSS_QUIRK_MMSS_GDSC_COLLAPSE);
mdss_set_quirk(mdata, MDSS_QUIRK_MDP_CLK_SET_RATE);
mdss_set_quirk(mdata, MDSS_QUIRK_DMA_BI_DIR);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index bd70535e79f9..49348e5e16a9 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -6061,6 +6061,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg,
mutex_lock(&ctl->mfd->bl_lock);
mdss_fb_set_backlight(ctl->mfd,
ctl->mfd->bl_extn_level);
+ ctl->mfd->bl_level_usr = ctl->mfd->bl_extn_level;
mutex_unlock(&ctl->mfd->bl_lock);
}
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index 3e6b576cfb6e..a3511a1a07ef 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -1710,12 +1710,42 @@ static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
return 0;
}
+static int mdss_mdp_video_splash_handoff(struct mdss_mdp_ctl *ctl)
+{
+ int i, ret = 0;
+ u32 data, flush;
+
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_BEGIN,
+ NULL, CTL_INTF_EVENT_FLAG_DEFAULT);
+
+ if (ret) {
+ pr_err("%s:ctl%d failed to handle 'CONT_SPLASH_BEGIN' event\n"
+ , __func__, ctl->num);
+ return ret;
+ }
+
+ /* clear up mixer0 and mixer1 */
+ flush = 0;
+ for (i = 0; i < 2; i++) {
+ data = mdss_mdp_ctl_read(ctl,
+ MDSS_MDP_REG_CTL_LAYER(i));
+ if (data) {
+ mdss_mdp_ctl_write(ctl,
+ MDSS_MDP_REG_CTL_LAYER(i),
+ MDSS_MDP_LM_BORDER_COLOR);
+ flush |= (0x40 << i);
+ }
+ }
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, flush);
+
+ return ret;
+}
+
int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl,
bool handoff)
{
struct mdss_panel_data *pdata;
- int i, ret = 0, off;
- u32 data, flush;
+ int ret = 0, off;
struct mdss_mdp_video_ctx *ctx, *sctx = NULL;
struct mdss_mdp_ctl *sctl;
@@ -1749,29 +1779,20 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl,
}
if (!handoff) {
- ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_CONT_SPLASH_BEGIN,
- NULL, CTL_INTF_EVENT_FLAG_DEFAULT);
- if (ret) {
- pr_err("%s: Failed to handle 'CONT_SPLASH_BEGIN' event\n"
- , __func__);
- return ret;
- }
+ ret = mdss_mdp_video_splash_handoff(ctl);
- /* clear up mixer0 and mixer1 */
- flush = 0;
- for (i = 0; i < 2; i++) {
- data = mdss_mdp_ctl_read(ctl,
- MDSS_MDP_REG_CTL_LAYER(i));
- if (data) {
- mdss_mdp_ctl_write(ctl,
- MDSS_MDP_REG_CTL_LAYER(i),
- MDSS_MDP_LM_BORDER_COLOR);
- flush |= (0x40 << i);
- }
- }
- mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, flush);
+ if (!ret && sctl)
+ ret = mdss_mdp_video_splash_handoff(sctl);
+
+ if (ret)
+ return ret;
mdp_video_write(ctx, MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
+
+ if (sctx)
+ mdp_video_write(sctx,
+ MDSS_MDP_REG_INTF_TIMING_ENGINE_EN, 0);
+
mdss_mdp_video_timegen_flush(ctl, sctx);
/* wait for 1 VSYNC for the pipe to be unstaged */
@@ -1780,6 +1801,12 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl,
ret = mdss_mdp_ctl_intf_event(ctl,
MDSS_EVENT_CONT_SPLASH_FINISH, NULL,
CTL_INTF_EVENT_FLAG_DEFAULT);
+
+ if (!ret && sctl)
+ ret = mdss_mdp_ctl_intf_event(sctl,
+ MDSS_EVENT_CONT_SPLASH_FINISH, NULL,
+ CTL_INTF_EVENT_FLAG_DEFAULT);
+
}
return ret;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
index 5b284e624c7f..87ed56028edd 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
@@ -602,9 +602,14 @@ int mdss_mdp_writeback_prepare_cwb(struct mdss_mdp_ctl *ctl,
mdss_mdp_irq_enable(MDSS_MDP_IRQ_TYPE_CWB_OVERFLOW, CWB_PPB_1);
}
- if (test_bit(MDSS_QOS_WB2_WRITE_GATHER_EN, ctl->mdata->mdss_qos_map))
+ if (test_bit(MDSS_QOS_WB2_WRITE_GATHER_EN, ctl->mdata->mdss_qos_map)) {
+ u32 reg = 0;
+
+ reg = MDSS_VBIF_READ(ctl->mdata,
+ MDSS_VBIF_WRITE_GATHER_EN, false);
MDSS_VBIF_WRITE(ctl->mdata, MDSS_VBIF_WRITE_GATHER_EN,
- BIT(6), false);
+ reg | BIT(6), false);
+ }
if (ctl->mdata->default_ot_wr_limit || ctl->mdata->default_ot_rd_limit)
mdss_mdp_set_ot_limit_wb(ctx, false);
@@ -1030,9 +1035,14 @@ static int mdss_mdp_writeback_display(struct mdss_mdp_ctl *ctl, void *arg)
return ret;
}
- if (test_bit(MDSS_QOS_WB2_WRITE_GATHER_EN, ctl->mdata->mdss_qos_map))
+ if (test_bit(MDSS_QOS_WB2_WRITE_GATHER_EN, ctl->mdata->mdss_qos_map)) {
+ u32 reg = 0;
+
+ reg = MDSS_VBIF_READ(ctl->mdata,
+ MDSS_VBIF_WRITE_GATHER_EN, false);
MDSS_VBIF_WRITE(ctl->mdata, MDSS_VBIF_WRITE_GATHER_EN,
- BIT(6), false);
+ reg | BIT(6), false);
+ }
mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
mdss_mdp_writeback_intr_done, ctl);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c
index fce667a2126d..09a34223c2a5 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_layer.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c
@@ -1222,6 +1222,15 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd,
goto end;
}
+ /* scaling is not allowed for solid_fill layers */
+ if ((pipe->flags & MDP_SOLID_FILL) &&
+ ((pipe->src.w != pipe->dst.w) ||
+ (pipe->src.h != pipe->dst.h))) {
+ pr_err("solid fill pipe:%d cannot have scaling\n", pipe->num);
+ ret = -EINVAL;
+ goto end;
+ }
+
/*
* unstage the pipe if it's current z_order does not match with new
* z_order because client may only call the validate.
@@ -2595,9 +2604,10 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
}
ds_data = commit->dest_scaler;
- if (test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map) &&
- ds_data && (ds_data->flags & MDP_DESTSCALER_ENABLE) &&
- commit->dest_scaler_cnt) {
+
+ if (test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map)
+ && ds_data && commit->dest_scaler_cnt
+ && (ds_data->flags & MDP_DESTSCALER_ENABLE)) {
/*
* Find out which DS block to use based on DS commit info
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 5daa8a7a2752..8eb12d764be3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -48,6 +48,12 @@
#define BUF_POOL_SIZE 32
+#define DFPS_DATA_MAX_HFP 8192
+#define DFPS_DATA_MAX_HBP 8192
+#define DFPS_DATA_MAX_HPW 8192
+#define DFPS_DATA_MAX_FPS 0x7fffffff
+#define DFPS_DATA_MAX_CLK_RATE 250000
+
static int mdss_mdp_overlay_free_fb_pipe(struct msm_fb_data_type *mfd);
static int mdss_mdp_overlay_fb_parse_dt(struct msm_fb_data_type *mfd);
static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd);
@@ -519,16 +525,16 @@ static int __mdss_mdp_validate_pxl_extn(struct mdss_mdp_pipe *pipe)
return 0;
}
+
static int __mdss_mdp_validate_qseed3_cfg(struct mdss_mdp_pipe *pipe)
{
int plane;
for (plane = 0; plane < MAX_PLANES; plane++) {
u32 hor_req_pixels, hor_fetch_pixels;
- u32 hor_ov_fetch, vert_ov_fetch;
u32 vert_req_pixels, vert_fetch_pixels;
- u32 src_w = DECIMATED_DIMENSION(pipe->src.w, pipe->horz_deci);
- u32 src_h = DECIMATED_DIMENSION(pipe->src.h, pipe->vert_deci);
+ u32 src_w = pipe->src.w;
+ u32 src_h = pipe->src.h;
/*
* plane 1 and 2 are for chroma and are same. While configuring
@@ -545,9 +551,8 @@ static int __mdss_mdp_validate_qseed3_cfg(struct mdss_mdp_pipe *pipe)
*/
if (plane == 1 && !pipe->horz_deci &&
((pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420) ||
- (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1))) {
+ (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1)))
src_w >>= 1;
- }
if (plane == 1 && !pipe->vert_deci &&
((pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420) ||
@@ -556,39 +561,37 @@ static int __mdss_mdp_validate_qseed3_cfg(struct mdss_mdp_pipe *pipe)
hor_req_pixels = pipe->scaler.num_ext_pxls_left[plane];
- hor_fetch_pixels = src_w +
- (pipe->scaler.left_ftch[plane] >> pipe->horz_deci) +
- pipe->scaler.left_rpt[plane] +
- (pipe->scaler.right_ftch[plane] >> pipe->horz_deci) +
- pipe->scaler.right_rpt[plane];
-
- hor_ov_fetch = src_w +
- (pipe->scaler.left_ftch[plane] >> pipe->horz_deci) +
- (pipe->scaler.right_ftch[plane] >> pipe->horz_deci);
+ /**
+ * libscaler provides the fetch values before decimation
+ * and the rpt values are always 0, since qseed3 block
+ * internally does the repeat.
+ */
+ hor_fetch_pixels = DECIMATED_DIMENSION(src_w +
+ (int8_t)(pipe->scaler.left_ftch[plane]
+ & 0xFF) +
+ (int8_t)(pipe->scaler.right_ftch[plane]
+ & 0xFF),
+ pipe->horz_deci);
vert_req_pixels = pipe->scaler.num_ext_pxls_top[plane];
- vert_fetch_pixels = src_h +
- (pipe->scaler.top_ftch[plane] >> pipe->vert_deci) +
- pipe->scaler.top_rpt[plane] +
- (pipe->scaler.btm_ftch[plane] >> pipe->vert_deci) +
- pipe->scaler.btm_rpt[plane];
-
- vert_ov_fetch = src_h +
- (pipe->scaler.top_ftch[plane] >> pipe->vert_deci) +
- (pipe->scaler.btm_ftch[plane] >> pipe->vert_deci);
+ vert_fetch_pixels = DECIMATED_DIMENSION(src_h +
+ (int8_t)(pipe->scaler.top_ftch[plane]
+ & 0xFF)+
+ (int8_t)(pipe->scaler.btm_ftch[plane]
+ & 0xFF),
+ pipe->vert_deci);
if ((hor_req_pixels != hor_fetch_pixels) ||
- (hor_ov_fetch > pipe->img_width) ||
+ (hor_fetch_pixels > pipe->img_width) ||
(vert_req_pixels != vert_fetch_pixels) ||
- (vert_ov_fetch > pipe->img_height)) {
- pr_err("err: plane=%d h_req:%d h_fetch:%d v_req:%d v_fetch:%d src_img[%d %d] ov_fetch[%d %d]\n",
+ (vert_fetch_pixels > pipe->img_height)) {
+ pr_err("err: plane=%d h_req:%d h_fetch:%d v_req:%d v_fetch:%d src_img[%d %d]\n",
plane,
hor_req_pixels, hor_fetch_pixels,
vert_req_pixels, vert_fetch_pixels,
- pipe->img_width, pipe->img_height,
- hor_ov_fetch, vert_ov_fetch);
+ pipe->img_width, pipe->img_height);
pipe->scaler.enable = 0;
return -EINVAL;
}
@@ -3519,6 +3522,13 @@ static ssize_t dynamic_fps_sysfs_wta_dfps(struct device *dev,
return count;
}
+ if (data.hfp > DFPS_DATA_MAX_HFP || data.hbp > DFPS_DATA_MAX_HBP ||
+ data.hpw > DFPS_DATA_MAX_HPW || data.fps > DFPS_DATA_MAX_FPS ||
+ data.clk_rate > DFPS_DATA_MAX_CLK_RATE){
+ pr_err("Data values out of bound.\n");
+ return -EINVAL;
+ }
+
rc = mdss_mdp_dfps_update_params(mfd, pdata, &data);
if (rc) {
pr_err("failed to set dfps params\n");
diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
index 0e0d2621496e..03e78733d168 100644
--- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c
+++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
@@ -1863,8 +1863,10 @@ static int mdss_dsi_ulps_config_default(struct mdss_dsi_ctrl_pdata *ctrl,
* to be in stop state.
*/
MIPI_OUTP(ctrl->ctrl_base + 0x0AC, active_lanes << 16);
+ wmb(); /* ensure lanes are put to stop state */
MIPI_OUTP(ctrl->ctrl_base + 0x0AC, 0x0);
+ wmb(); /* ensure lanes are in proper state */
lane_status = MIPI_INP(ctrl->ctrl_base + 0xA8);
}
@@ -2272,6 +2274,8 @@ int mdss_dsi_pre_clkoff_cb(void *priv,
pdata = &ctrl->panel_data;
if ((clk & MDSS_DSI_LINK_CLK) && (new_state == MDSS_DSI_CLK_OFF)) {
+ if (pdata->panel_info.mipi.force_clk_lane_hs)
+ mdss_dsi_cfg_lane_ctrl(ctrl, BIT(28), 0);
/*
* If ULPS feature is enabled, enter ULPS first.
* However, when blanking the panel, we should enter ULPS
@@ -2387,6 +2391,8 @@ int mdss_dsi_post_clkon_cb(void *priv,
goto error;
}
}
+ if (pdata->panel_info.mipi.force_clk_lane_hs)
+ mdss_dsi_cfg_lane_ctrl(ctrl, BIT(28), 1);
}
error:
return rc;
diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c
index 049a884a756f..59d74d1b47a8 100644
--- a/drivers/w1/masters/ds2490.c
+++ b/drivers/w1/masters/ds2490.c
@@ -153,6 +153,9 @@ struct ds_device
*/
u16 spu_bit;
+ u8 st_buf[ST_SIZE];
+ u8 byte_buf;
+
struct w1_bus_master master;
};
@@ -174,7 +177,6 @@ struct ds_status
u8 data_in_buffer_status;
u8 reserved1;
u8 reserved2;
-
};
static struct usb_device_id ds_id_table [] = {
@@ -244,28 +246,6 @@ static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
return err;
}
-static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
- unsigned char *buf, int size)
-{
- int count, err;
-
- memset(st, 0, sizeof(*st));
-
- count = 0;
- err = usb_interrupt_msg(dev->udev, usb_rcvintpipe(dev->udev,
- dev->ep[EP_STATUS]), buf, size, &count, 1000);
- if (err < 0) {
- pr_err("Failed to read 1-wire data from 0x%x: err=%d.\n",
- dev->ep[EP_STATUS], err);
- return err;
- }
-
- if (count >= sizeof(*st))
- memcpy(st, buf, sizeof(*st));
-
- return count;
-}
-
static inline void ds_print_msg(unsigned char *buf, unsigned char *str, int off)
{
pr_info("%45s: %8x\n", str, buf[off]);
@@ -324,6 +304,35 @@ static void ds_dump_status(struct ds_device *dev, unsigned char *buf, int count)
}
}
+static int ds_recv_status(struct ds_device *dev, struct ds_status *st,
+ bool dump)
+{
+ int count, err;
+
+ if (st)
+ memset(st, 0, sizeof(*st));
+
+ count = 0;
+ err = usb_interrupt_msg(dev->udev,
+ usb_rcvintpipe(dev->udev,
+ dev->ep[EP_STATUS]),
+ dev->st_buf, sizeof(dev->st_buf),
+ &count, 1000);
+ if (err < 0) {
+ pr_err("Failed to read 1-wire data from 0x%x: err=%d.\n",
+ dev->ep[EP_STATUS], err);
+ return err;
+ }
+
+ if (dump)
+ ds_dump_status(dev, dev->st_buf, count);
+
+ if (st && count >= sizeof(*st))
+ memcpy(st, dev->st_buf, sizeof(*st));
+
+ return count;
+}
+
static void ds_reset_device(struct ds_device *dev)
{
ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
@@ -344,7 +353,6 @@ static void ds_reset_device(struct ds_device *dev)
static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
{
int count, err;
- struct ds_status st;
/* Careful on size. If size is less than what is available in
* the input buffer, the device fails the bulk transfer and
@@ -359,14 +367,9 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
buf, size, &count, 1000);
if (err < 0) {
- u8 buf[ST_SIZE];
- int count;
-
pr_info("Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]));
-
- count = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
- ds_dump_status(dev, buf, count);
+ ds_recv_status(dev, NULL, true);
return err;
}
@@ -404,7 +407,6 @@ int ds_stop_pulse(struct ds_device *dev, int limit)
{
struct ds_status st;
int count = 0, err = 0;
- u8 buf[ST_SIZE];
do {
err = ds_send_control(dev, CTL_HALT_EXE_IDLE, 0);
@@ -413,7 +415,7 @@ int ds_stop_pulse(struct ds_device *dev, int limit)
err = ds_send_control(dev, CTL_RESUME_EXE, 0);
if (err)
break;
- err = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
+ err = ds_recv_status(dev, &st, false);
if (err)
break;
@@ -456,18 +458,17 @@ int ds_detect(struct ds_device *dev, struct ds_status *st)
static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
{
- u8 buf[ST_SIZE];
int err, count = 0;
do {
st->status = 0;
- err = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
+ err = ds_recv_status(dev, st, false);
#if 0
if (err >= 0) {
int i;
printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], err);
for (i=0; i<err; ++i)
- printk("%02x ", buf[i]);
+ printk("%02x ", dev->st_buf[i]);
printk("\n");
}
#endif
@@ -485,7 +486,7 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
* can do something with it).
*/
if (err > 16 || count >= 100 || err < 0)
- ds_dump_status(dev, buf, err);
+ ds_dump_status(dev, dev->st_buf, err);
/* Extended data isn't an error. Well, a short is, but the dump
* would have already told the user that and we can't do anything
@@ -608,7 +609,6 @@ static int ds_write_byte(struct ds_device *dev, u8 byte)
{
int err;
struct ds_status st;
- u8 rbyte;
err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | dev->spu_bit, byte);
if (err)
@@ -621,11 +621,11 @@ static int ds_write_byte(struct ds_device *dev, u8 byte)
if (err)
return err;
- err = ds_recv_data(dev, &rbyte, sizeof(rbyte));
+ err = ds_recv_data(dev, &dev->byte_buf, 1);
if (err < 0)
return err;
- return !(byte == rbyte);
+ return !(byte == dev->byte_buf);
}
static int ds_read_byte(struct ds_device *dev, u8 *byte)
@@ -712,7 +712,6 @@ static void ds9490r_search(void *data, struct w1_master *master,
int err;
u16 value, index;
struct ds_status st;
- u8 st_buf[ST_SIZE];
int search_limit;
int found = 0;
int i;
@@ -724,7 +723,12 @@ static void ds9490r_search(void *data, struct w1_master *master,
/* FIFO 128 bytes, bulk packet size 64, read a multiple of the
* packet size.
*/
- u64 buf[2*64/8];
+ const size_t bufsize = 2 * 64;
+ u64 *buf;
+
+ buf = kmalloc(bufsize, GFP_KERNEL);
+ if (!buf)
+ return;
mutex_lock(&master->bus_mutex);
@@ -745,10 +749,9 @@ static void ds9490r_search(void *data, struct w1_master *master,
do {
schedule_timeout(jtime);
- if (ds_recv_status_nodump(dev, &st, st_buf, sizeof(st_buf)) <
- sizeof(st)) {
+ err = ds_recv_status(dev, &st, false);
+ if (err < 0 || err < sizeof(st))
break;
- }
if (st.data_in_buffer_status) {
/* Bulk in can receive partial ids, but when it does
@@ -758,7 +761,7 @@ static void ds9490r_search(void *data, struct w1_master *master,
* bulk without first checking if status says there
* is data to read.
*/
- err = ds_recv_data(dev, (u8 *)buf, sizeof(buf));
+ err = ds_recv_data(dev, (u8 *)buf, bufsize);
if (err < 0)
break;
for (i = 0; i < err/8; ++i) {
@@ -794,9 +797,14 @@ static void ds9490r_search(void *data, struct w1_master *master,
}
search_out:
mutex_unlock(&master->bus_mutex);
+ kfree(buf);
}
#if 0
+/*
+ * FIXME: if this disabled code is ever used in the future all ds_send_data()
+ * calls must be changed to use a DMAable buffer.
+ */
static int ds_match_access(struct ds_device *dev, u64 init)
{
int err;
@@ -845,13 +853,12 @@ static int ds_set_path(struct ds_device *dev, u64 init)
static u8 ds9490r_touch_bit(void *data, u8 bit)
{
- u8 ret;
struct ds_device *dev = data;
- if (ds_touch_bit(dev, bit, &ret))
+ if (ds_touch_bit(dev, bit, &dev->byte_buf))
return 0;
- return ret;
+ return dev->byte_buf;
}
#if 0
@@ -866,13 +873,12 @@ static u8 ds9490r_read_bit(void *data)
{
struct ds_device *dev = data;
int err;
- u8 bit = 0;
- err = ds_touch_bit(dev, 1, &bit);
+ err = ds_touch_bit(dev, 1, &dev->byte_buf);
if (err)
return 0;
- return bit & 1;
+ return dev->byte_buf & 1;
}
#endif
@@ -887,32 +893,52 @@ static u8 ds9490r_read_byte(void *data)
{
struct ds_device *dev = data;
int err;
- u8 byte = 0;
- err = ds_read_byte(dev, &byte);
+ err = ds_read_byte(dev, &dev->byte_buf);
if (err)
return 0;
- return byte;
+ return dev->byte_buf;
}
static void ds9490r_write_block(void *data, const u8 *buf, int len)
{
struct ds_device *dev = data;
+ u8 *tbuf;
+
+ if (len <= 0)
+ return;
+
+ tbuf = kmalloc(len, GFP_KERNEL);
+ if (!tbuf)
+ return;
- ds_write_block(dev, (u8 *)buf, len);
+ memcpy(tbuf, buf, len);
+ ds_write_block(dev, tbuf, len);
+
+ kfree(tbuf);
}
static u8 ds9490r_read_block(void *data, u8 *buf, int len)
{
struct ds_device *dev = data;
int err;
+ u8 *tbuf;
- err = ds_read_block(dev, buf, len);
- if (err < 0)
+ if (len <= 0)
+ return 0;
+
+ tbuf = kmalloc(len, GFP_KERNEL);
+ if (!tbuf)
return 0;
- return len;
+ err = ds_read_block(dev, tbuf, len);
+ if (err >= 0)
+ memcpy(buf, tbuf, len);
+
+ kfree(tbuf);
+
+ return err >= 0 ? len : 0;
}
static u8 ds9490r_reset(void *data)
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index c9a7ff67d395..39886edfa222 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -763,6 +763,7 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
dev_err(&dev->dev, "%s: Attaching %s failed.\n", __func__,
sl->name);
w1_family_put(sl->family);
+ atomic_dec(&sl->master->refcnt);
kfree(sl);
return err;
}
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 239bc9cba28c..f54f77037d22 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -644,6 +644,9 @@ static void __unregister_request(struct ceph_mds_client *mdsc,
{
dout("__unregister_request %p tid %lld\n", req, req->r_tid);
+ /* Never leave an unregistered request on an unsafe list! */
+ list_del_init(&req->r_unsafe_item);
+
if (req->r_tid == mdsc->oldest_tid) {
struct rb_node *p = rb_next(&req->r_node);
mdsc->oldest_tid = 0;
@@ -1051,7 +1054,6 @@ static void cleanup_session_requests(struct ceph_mds_client *mdsc,
while (!list_empty(&session->s_unsafe)) {
req = list_first_entry(&session->s_unsafe,
struct ceph_mds_request, r_unsafe_item);
- list_del_init(&req->r_unsafe_item);
pr_warn_ratelimited(" dropping unsafe request %llu\n",
req->r_tid);
__unregister_request(mdsc, req);
@@ -2477,7 +2479,6 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
* useful we could do with a revised return value.
*/
dout("got safe reply %llu, mds%d\n", tid, mds);
- list_del_init(&req->r_unsafe_item);
/* last unsafe request during umount? */
if (mdsc->stopping && !__get_oldest_req(mdsc))
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 9da42ace762a..8a456f9b8a44 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -5362,7 +5362,8 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
ext4_lblk_t stop, *iterator, ex_start, ex_end;
/* Let path point to the last extent */
- path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL, 0);
+ path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL,
+ EXT4_EX_NOCACHE);
if (IS_ERR(path))
return PTR_ERR(path);
@@ -5371,15 +5372,15 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
if (!extent)
goto out;
- stop = le32_to_cpu(extent->ee_block) +
- ext4_ext_get_actual_len(extent);
+ stop = le32_to_cpu(extent->ee_block);
/*
* In case of left shift, Don't start shifting extents until we make
* sure the hole is big enough to accommodate the shift.
*/
if (SHIFT == SHIFT_LEFT) {
- path = ext4_find_extent(inode, start - 1, &path, 0);
+ path = ext4_find_extent(inode, start - 1, &path,
+ EXT4_EX_NOCACHE);
if (IS_ERR(path))
return PTR_ERR(path);
depth = path->p_depth;
@@ -5411,9 +5412,14 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
else
iterator = &stop;
- /* Its safe to start updating extents */
- while (start < stop) {
- path = ext4_find_extent(inode, *iterator, &path, 0);
+ /*
+ * Its safe to start updating extents. Start and stop are unsigned, so
+ * in case of right shift if extent with 0 block is reached, iterator
+ * becomes NULL to indicate the end of the loop.
+ */
+ while (iterator && start <= stop) {
+ path = ext4_find_extent(inode, *iterator, &path,
+ EXT4_EX_NOCACHE);
if (IS_ERR(path))
return PTR_ERR(path);
depth = path->p_depth;
@@ -5440,8 +5446,11 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
ext4_ext_get_actual_len(extent);
} else {
extent = EXT_FIRST_EXTENT(path[depth].p_hdr);
- *iterator = le32_to_cpu(extent->ee_block) > 0 ?
- le32_to_cpu(extent->ee_block) - 1 : 0;
+ if (le32_to_cpu(extent->ee_block) > 0)
+ *iterator = le32_to_cpu(extent->ee_block) - 1;
+ else
+ /* Beginning is reached, end of the loop */
+ iterator = NULL;
/* Update path extent in case we need to stop */
while (le32_to_cpu(extent->ee_block) < start)
extent++;
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 66eed657701c..cb3d6f6419cd 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -933,8 +933,15 @@ int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
struct page *page)
{
int i_size_changed = 0;
+ int ret;
- copied = ext4_write_inline_data_end(inode, pos, len, copied, page);
+ ret = ext4_write_inline_data_end(inode, pos, len, copied, page);
+ if (ret < 0) {
+ unlock_page(page);
+ put_page(page);
+ return ret;
+ }
+ copied = ret;
/*
* No need to use i_size_read() here, the i_size
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 55841e20ec3e..99fa2fca52b1 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1167,8 +1167,11 @@ static int ext4_write_end(struct file *file,
if (ext4_has_inline_data(inode)) {
ret = ext4_write_inline_data_end(inode, pos, len,
copied, page);
- if (ret < 0)
+ if (ret < 0) {
+ unlock_page(page);
+ put_page(page);
goto errout;
+ }
copied = ret;
} else
copied = block_write_end(file, mapping, pos,
@@ -1222,7 +1225,9 @@ errout:
* set the buffer to be dirty, since in data=journalled mode we need
* to call ext4_handle_dirty_metadata() instead.
*/
-static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
+static void ext4_journalled_zero_new_buffers(handle_t *handle,
+ struct page *page,
+ unsigned from, unsigned to)
{
unsigned int block_start = 0, block_end;
struct buffer_head *head, *bh;
@@ -1239,7 +1244,7 @@ static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
size = min(to, block_end) - start;
zero_user(page, start, size);
- set_buffer_uptodate(bh);
+ write_end_fn(handle, bh);
}
clear_buffer_new(bh);
}
@@ -1268,18 +1273,25 @@ static int ext4_journalled_write_end(struct file *file,
BUG_ON(!ext4_handle_valid(handle));
- if (ext4_has_inline_data(inode))
- copied = ext4_write_inline_data_end(inode, pos, len,
- copied, page);
- else {
- if (copied < len) {
- if (!PageUptodate(page))
- copied = 0;
- zero_new_buffers(page, from+copied, to);
+ if (ext4_has_inline_data(inode)) {
+ ret = ext4_write_inline_data_end(inode, pos, len,
+ copied, page);
+ if (ret < 0) {
+ unlock_page(page);
+ put_page(page);
+ goto errout;
}
-
+ copied = ret;
+ } else if (unlikely(copied < len) && !PageUptodate(page)) {
+ copied = 0;
+ ext4_journalled_zero_new_buffers(handle, page, from, to);
+ } else {
+ if (unlikely(copied < len))
+ ext4_journalled_zero_new_buffers(handle, page,
+ from + copied, to);
ret = ext4_walk_page_buffers(handle, page_buffers(page), from,
- to, &partial, write_end_fn);
+ from + copied, &partial,
+ write_end_fn);
if (!partial)
SetPageUptodate(page);
}
@@ -1305,6 +1317,7 @@ static int ext4_journalled_write_end(struct file *file,
*/
ext4_orphan_add(handle, inode);
+errout:
ret2 = ext4_journal_stop(handle);
if (!ret)
ret = ret2;
@@ -3567,6 +3580,10 @@ static int ext4_block_truncate_page(handle_t *handle,
unsigned blocksize;
struct inode *inode = mapping->host;
+ /* If we are processing an encrypted inode during orphan list handling */
+ if (ext4_encrypted_inode(inode) && !ext4_has_encryption_key(inode))
+ return 0;
+
blocksize = inode->i_sb->s_blocksize;
length = blocksize - (offset & (blocksize - 1));
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index be1227c196d8..c2810503eb50 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -3121,6 +3121,13 @@ ext4_mb_normalize_request(struct ext4_allocation_context *ac,
if (ar->pright && start + size - 1 >= ar->lright)
size -= start + size - ar->lright;
+ /*
+ * Trim allocation request for filesystems with artificially small
+ * groups.
+ */
+ if (size > EXT4_BLOCKS_PER_GROUP(ac->ac_sb))
+ size = EXT4_BLOCKS_PER_GROUP(ac->ac_sb);
+
end = start + size;
/* check we don't cross already preallocated blocks */
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index b405a7b74ce0..6fe8e30eeb99 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -793,6 +793,7 @@ static void ext4_put_super(struct super_block *sb)
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
struct ext4_super_block *es = sbi->s_es;
+ int aborted = 0;
int i, err;
ext4_unregister_li_request(sb);
@@ -802,9 +803,10 @@ static void ext4_put_super(struct super_block *sb)
destroy_workqueue(sbi->rsv_conversion_wq);
if (sbi->s_journal) {
+ aborted = is_journal_aborted(sbi->s_journal);
err = jbd2_journal_destroy(sbi->s_journal);
sbi->s_journal = NULL;
- if (err < 0)
+ if ((err < 0) && !aborted)
ext4_abort(sb, "Couldn't clean up the journal");
}
@@ -816,7 +818,7 @@ static void ext4_put_super(struct super_block *sb)
ext4_ext_release(sb);
ext4_xattr_put_super(sb);
- if (!(sb->s_flags & MS_RDONLY)) {
+ if (!(sb->s_flags & MS_RDONLY) && !aborted) {
ext4_clear_feature_journal_needs_recovery(sb);
es->s_state = cpu_to_le16(sbi->s_mount_state);
}
@@ -3746,7 +3748,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
* root first: it may be modified in the journal!
*/
if (!test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb)) {
- if (ext4_load_journal(sb, es, journal_devnum))
+ err = ext4_load_journal(sb, es, journal_devnum);
+ if (err)
goto failed_mount3a;
} else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) &&
ext4_has_feature_journal_needs_recovery(sb)) {
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 972eab7ac071..f53826ec30f3 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -742,6 +742,10 @@ static int get_data_block_dio(struct inode *inode, sector_t iblock,
static int get_data_block_bmap(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
+ /* Block number less than F2FS MAX BLOCKS */
+ if (unlikely(iblock >= max_file_size(0)))
+ return -EFBIG;
+
return __get_data_block(inode, iblock, bh_result, create,
F2FS_GET_BLOCK_BMAP);
}
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 9db5500d63d9..3c7594b9d109 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1715,6 +1715,7 @@ static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
* super.c
*/
int f2fs_commit_super(struct f2fs_sb_info *, bool);
+loff_t max_file_size(unsigned bits);
int f2fs_sync_fs(struct super_block *, int);
extern __printf(3, 4)
void f2fs_msg(struct super_block *, const char *, const char *, ...);
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 3a65e0132352..106dda1e743d 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -898,7 +898,7 @@ static const struct export_operations f2fs_export_ops = {
.get_parent = f2fs_get_parent,
};
-static loff_t max_file_size(unsigned bits)
+loff_t max_file_size(unsigned bits)
{
loff_t result = (DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS);
loff_t leaf_count = ADDRS_PER_BLOCK;
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c
index 8226557130a2..6abd78629140 100644
--- a/fs/fat/fatent.c
+++ b/fs/fat/fatent.c
@@ -92,7 +92,8 @@ static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent,
err_brelse:
brelse(bhs[0]);
err:
- fat_msg(sb, KERN_ERR, "FAT read failed (blocknr %llu)", (llu)blocknr);
+ fat_msg_ratelimit(sb, KERN_ERR,
+ "FAT read failed (blocknr %llu)", (llu)blocknr);
return -EIO;
}
@@ -105,8 +106,8 @@ static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent,
fatent->fat_inode = MSDOS_SB(sb)->fat_inode;
fatent->bhs[0] = sb_bread(sb, blocknr);
if (!fatent->bhs[0]) {
- fat_msg(sb, KERN_ERR, "FAT read failed (blocknr %llu)",
- (llu)blocknr);
+ fat_msg_ratelimit(sb, KERN_ERR,
+ "FAT read failed (blocknr %llu)", (llu)blocknr);
return -EIO;
}
fatent->nr_bhs = 1;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 509411dd3698..a6c21fba6e9f 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -760,8 +760,9 @@ retry:
fat_get_blknr_offset(sbi, i_pos, &blocknr, &offset);
bh = sb_bread(sb, blocknr);
if (!bh) {
- fat_msg(sb, KERN_ERR, "unable to read inode block "
- "for updating (i_pos %lld)", i_pos);
+ fat_msg_ratelimit(sb, KERN_ERR,
+ "unable to read inode block for updating (i_pos %lld)",
+ i_pos);
return -EIO;
}
spin_lock(&sbi->inode_hash_lock);
@@ -1269,6 +1270,16 @@ out:
return 0;
}
+static void fat_dummy_inode_init(struct inode *inode)
+{
+ /* Initialize this dummy inode to work as no-op. */
+ MSDOS_I(inode)->mmu_private = 0;
+ MSDOS_I(inode)->i_start = 0;
+ MSDOS_I(inode)->i_logstart = 0;
+ MSDOS_I(inode)->i_attrs = 0;
+ MSDOS_I(inode)->i_pos = 0;
+}
+
static int fat_read_root(struct inode *inode)
{
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
@@ -1713,12 +1724,13 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
fat_inode = new_inode(sb);
if (!fat_inode)
goto out_fail;
- MSDOS_I(fat_inode)->i_pos = 0;
+ fat_dummy_inode_init(fat_inode);
sbi->fat_inode = fat_inode;
fsinfo_inode = new_inode(sb);
if (!fsinfo_inode)
goto out_fail;
+ fat_dummy_inode_init(fsinfo_inode);
fsinfo_inode->i_ino = MSDOS_FSINFO_INO;
sbi->fsinfo_inode = fsinfo_inode;
insert_inode_hash(fsinfo_inode);
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 64eb2c6ee450..66b34b14cb6b 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -113,6 +113,7 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
iput(req->misc.release.inode);
fuse_put_request(ff->fc, req);
} else if (sync) {
+ __set_bit(FR_FORCE, &req->flags);
__clear_bit(FR_BACKGROUND, &req->flags);
fuse_request_send(ff->fc, req);
iput(req->misc.release.inode);
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 32e74710b1aa..9cd8c92b953d 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -651,9 +651,11 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
struct kmem_cache *cachep;
int ret, tries = 0;
+ rcu_read_lock();
gl = rhashtable_lookup_fast(&gl_hash_table, &name, ht_parms);
if (gl && !lockref_get_not_dead(&gl->gl_lockref))
gl = NULL;
+ rcu_read_unlock();
*glp = gl;
if (gl)
@@ -721,15 +723,18 @@ again:
if (ret == -EEXIST) {
ret = 0;
+ rcu_read_lock();
tmp = rhashtable_lookup_fast(&gl_hash_table, &name, ht_parms);
if (tmp == NULL || !lockref_get_not_dead(&tmp->gl_lockref)) {
if (++tries < 100) {
+ rcu_read_unlock();
cond_resched();
goto again;
}
tmp = NULL;
ret = -ENOMEM;
}
+ rcu_read_unlock();
} else {
WARN_ON_ONCE(ret);
}
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index fa1b8e0dcacf..a2e724053919 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -1876,7 +1876,9 @@ static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
__blist_del_buffer(list, jh);
jh->b_jlist = BJ_None;
- if (test_clear_buffer_jbddirty(bh))
+ if (transaction && is_journal_aborted(transaction->t_journal))
+ clear_buffer_jbddirty(bh);
+ else if (test_clear_buffer_jbddirty(bh))
mark_buffer_dirty(bh); /* Expose it to the VM */
}
diff --git a/fs/mount.h b/fs/mount.h
index 14db05d424f7..3dc7dea5a357 100644
--- a/fs/mount.h
+++ b/fs/mount.h
@@ -86,7 +86,6 @@ static inline int is_mounted(struct vfsmount *mnt)
}
extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *);
-extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *);
extern int __legitimize_mnt(struct vfsmount *, unsigned);
extern bool legitimize_mnt(struct vfsmount *, unsigned);
diff --git a/fs/namespace.c b/fs/namespace.c
index 4aad64ad9ad0..c1477882a853 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -639,28 +639,6 @@ struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
}
/*
- * find the last mount at @dentry on vfsmount @mnt.
- * mount_lock must be held.
- */
-struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry)
-{
- struct mount *p, *res = NULL;
- p = __lookup_mnt(mnt, dentry);
- if (!p)
- goto out;
- if (!(p->mnt.mnt_flags & MNT_UMOUNT))
- res = p;
- hlist_for_each_entry_continue(p, mnt_hash) {
- if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry)
- break;
- if (!(p->mnt.mnt_flags & MNT_UMOUNT))
- res = p;
- }
-out:
- return res;
-}
-
-/*
* lookup_mnt - Return the first child mount mounted at path
*
* "First" means first mounted chronologically. If you create the
@@ -880,6 +858,13 @@ void mnt_set_mountpoint(struct mount *mnt,
hlist_add_head(&child_mnt->mnt_mp_list, &mp->m_list);
}
+static void __attach_mnt(struct mount *mnt, struct mount *parent)
+{
+ hlist_add_head_rcu(&mnt->mnt_hash,
+ m_hash(&parent->mnt, mnt->mnt_mountpoint));
+ list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
+}
+
/*
* vfsmount lock must be held for write
*/
@@ -888,28 +873,45 @@ static void attach_mnt(struct mount *mnt,
struct mountpoint *mp)
{
mnt_set_mountpoint(parent, mp, mnt);
- hlist_add_head_rcu(&mnt->mnt_hash, m_hash(&parent->mnt, mp->m_dentry));
- list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
+ __attach_mnt(mnt, parent);
}
-static void attach_shadowed(struct mount *mnt,
- struct mount *parent,
- struct mount *shadows)
+void mnt_change_mountpoint(struct mount *parent, struct mountpoint *mp, struct mount *mnt)
{
- if (shadows) {
- hlist_add_behind_rcu(&mnt->mnt_hash, &shadows->mnt_hash);
- list_add(&mnt->mnt_child, &shadows->mnt_child);
- } else {
- hlist_add_head_rcu(&mnt->mnt_hash,
- m_hash(&parent->mnt, mnt->mnt_mountpoint));
- list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
- }
+ struct mountpoint *old_mp = mnt->mnt_mp;
+ struct dentry *old_mountpoint = mnt->mnt_mountpoint;
+ struct mount *old_parent = mnt->mnt_parent;
+
+ list_del_init(&mnt->mnt_child);
+ hlist_del_init(&mnt->mnt_mp_list);
+ hlist_del_init_rcu(&mnt->mnt_hash);
+
+ attach_mnt(mnt, parent, mp);
+
+ put_mountpoint(old_mp);
+
+ /*
+ * Safely avoid even the suggestion this code might sleep or
+ * lock the mount hash by taking advantage of the knowledge that
+ * mnt_change_mountpoint will not release the final reference
+ * to a mountpoint.
+ *
+ * During mounting, the mount passed in as the parent mount will
+ * continue to use the old mountpoint and during unmounting, the
+ * old mountpoint will continue to exist until namespace_unlock,
+ * which happens well after mnt_change_mountpoint.
+ */
+ spin_lock(&old_mountpoint->d_lock);
+ old_mountpoint->d_lockref.count--;
+ spin_unlock(&old_mountpoint->d_lock);
+
+ mnt_add_count(old_parent, -1);
}
/*
* vfsmount lock must be held for write
*/
-static void commit_tree(struct mount *mnt, struct mount *shadows)
+static void commit_tree(struct mount *mnt)
{
struct mount *parent = mnt->mnt_parent;
struct mount *m;
@@ -924,7 +926,7 @@ static void commit_tree(struct mount *mnt, struct mount *shadows)
list_splice(&head, n->list.prev);
- attach_shadowed(mnt, parent, shadows);
+ __attach_mnt(mnt, parent);
touch_mnt_namespace(n);
}
@@ -1738,7 +1740,6 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
continue;
for (s = r; s; s = next_mnt(s, r)) {
- struct mount *t = NULL;
if (!(flag & CL_COPY_UNBINDABLE) &&
IS_MNT_UNBINDABLE(s)) {
s = skip_mnt_tree(s);
@@ -1760,14 +1761,7 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
goto out;
lock_mount_hash();
list_add_tail(&q->mnt_list, &res->mnt_list);
- mnt_set_mountpoint(parent, p->mnt_mp, q);
- if (!list_empty(&parent->mnt_mounts)) {
- t = list_last_entry(&parent->mnt_mounts,
- struct mount, mnt_child);
- if (t->mnt_mp != p->mnt_mp)
- t = NULL;
- }
- attach_shadowed(q, parent, t);
+ attach_mnt(q, parent, p->mnt_mp);
unlock_mount_hash();
}
}
@@ -1945,10 +1939,18 @@ static int attach_recursive_mnt(struct mount *source_mnt,
struct path *parent_path)
{
HLIST_HEAD(tree_list);
+ struct mountpoint *smp;
struct mount *child, *p;
struct hlist_node *n;
int err;
+ /* Preallocate a mountpoint in case the new mounts need
+ * to be tucked under other mounts.
+ */
+ smp = get_mountpoint(source_mnt->mnt.mnt_root);
+ if (IS_ERR(smp))
+ return PTR_ERR(smp);
+
if (IS_MNT_SHARED(dest_mnt)) {
err = invent_group_ids(source_mnt, true);
if (err)
@@ -1968,16 +1970,19 @@ static int attach_recursive_mnt(struct mount *source_mnt,
touch_mnt_namespace(source_mnt->mnt_ns);
} else {
mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt);
- commit_tree(source_mnt, NULL);
+ commit_tree(source_mnt);
}
hlist_for_each_entry_safe(child, n, &tree_list, mnt_hash) {
struct mount *q;
hlist_del_init(&child->mnt_hash);
- q = __lookup_mnt_last(&child->mnt_parent->mnt,
- child->mnt_mountpoint);
- commit_tree(child, q);
+ q = __lookup_mnt(&child->mnt_parent->mnt,
+ child->mnt_mountpoint);
+ if (q)
+ mnt_change_mountpoint(child, smp, q);
+ commit_tree(child);
}
+ put_mountpoint(smp);
unlock_mount_hash();
return 0;
@@ -1990,6 +1995,10 @@ static int attach_recursive_mnt(struct mount *source_mnt,
unlock_mount_hash();
cleanup_group_ids(source_mnt, NULL);
out:
+ read_seqlock_excl(&mount_lock);
+ put_mountpoint(smp);
+ read_sequnlock_excl(&mount_lock);
+
return err;
}
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 9a524e763c3e..4e3679b25b9b 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2452,6 +2452,7 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
ret = PTR_ERR(state);
if (IS_ERR(state))
goto out;
+ ctx->state = state;
if (server->caps & NFS_CAP_POSIX_LOCK)
set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
@@ -2474,7 +2475,6 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
if (ret != 0)
goto out;
- ctx->state = state;
if (d_inode(dentry) == state->inode) {
nfs_inode_attach_open_context(ctx);
if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
@@ -4711,7 +4711,7 @@ out:
*/
static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
{
- struct page *pages[NFS4ACL_MAXPAGES] = {NULL, };
+ struct page *pages[NFS4ACL_MAXPAGES + 1] = {NULL, };
struct nfs_getaclargs args = {
.fh = NFS_FH(inode),
.acl_pages = pages,
@@ -4725,13 +4725,9 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
.rpc_argp = &args,
.rpc_resp = &res,
};
- unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
+ unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1;
int ret = -ENOMEM, i;
- /* As long as we're doing a round trip to the server anyway,
- * let's be prepared for a page of acl data. */
- if (npages == 0)
- npages = 1;
if (npages > ARRAY_SIZE(pages))
return -ERANGE;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 4e4441216804..1cb50bb898b0 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -2487,7 +2487,7 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
encode_compound_hdr(xdr, req, &hdr);
encode_sequence(xdr, &args->seq_args, &hdr);
encode_putfh(xdr, args->fh, &hdr);
- replen = hdr.replen + op_decode_hdr_maxsz + 1;
+ replen = hdr.replen + op_decode_hdr_maxsz;
encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr);
xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 994d66fbb446..91e0c5429b4d 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -369,7 +369,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
__be32 err;
int host_err;
bool get_write_count;
- int size_change = 0;
+ bool size_change = (iap->ia_valid & ATTR_SIZE);
if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
@@ -382,11 +382,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
/* Get inode */
err = fh_verify(rqstp, fhp, ftype, accmode);
if (err)
- goto out;
+ return err;
if (get_write_count) {
host_err = fh_want_write(fhp);
if (host_err)
- return nfserrno(host_err);
+ goto out;
}
dentry = fhp->fh_dentry;
@@ -397,20 +397,28 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
iap->ia_valid &= ~ATTR_MODE;
if (!iap->ia_valid)
- goto out;
+ return 0;
nfsd_sanitize_attrs(inode, iap);
+ if (check_guard && guardtime != inode->i_ctime.tv_sec)
+ return nfserr_notsync;
+
/*
* The size case is special, it changes the file in addition to the
- * attributes.
+ * attributes, and file systems don't expect it to be mixed with
+ * "random" attribute changes. We thus split out the size change
+ * into a separate call to ->setattr, and do the rest as a separate
+ * setattr call.
*/
- if (iap->ia_valid & ATTR_SIZE) {
+ if (size_change) {
err = nfsd_get_write_access(rqstp, fhp, iap);
if (err)
- goto out;
- size_change = 1;
+ return err;
+ }
+ fh_lock(fhp);
+ if (size_change) {
/*
* RFC5661, Section 18.30.4:
* Changing the size of a file with SETATTR indirectly
@@ -418,29 +426,36 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
*
* (and similar for the older RFCs)
*/
- if (iap->ia_size != i_size_read(inode))
- iap->ia_valid |= ATTR_MTIME;
- }
+ struct iattr size_attr = {
+ .ia_valid = ATTR_SIZE | ATTR_CTIME | ATTR_MTIME,
+ .ia_size = iap->ia_size,
+ };
- iap->ia_valid |= ATTR_CTIME;
+ host_err = notify_change(dentry, &size_attr, NULL);
+ if (host_err)
+ goto out_unlock;
+ iap->ia_valid &= ~ATTR_SIZE;
- if (check_guard && guardtime != inode->i_ctime.tv_sec) {
- err = nfserr_notsync;
- goto out_put_write_access;
+ /*
+ * Avoid the additional setattr call below if the only other
+ * attribute that the client sends is the mtime, as we update
+ * it as part of the size change above.
+ */
+ if ((iap->ia_valid & ~ATTR_MTIME) == 0)
+ goto out_unlock;
}
- fh_lock(fhp);
+ iap->ia_valid |= ATTR_CTIME;
host_err = notify_change(dentry, iap, NULL);
- fh_unlock(fhp);
- err = nfserrno(host_err);
-out_put_write_access:
+out_unlock:
+ fh_unlock(fhp);
if (size_change)
put_write_access(inode);
- if (!err)
- err = nfserrno(commit_metadata(fhp));
out:
- return err;
+ if (!host_err)
+ host_err = commit_metadata(fhp);
+ return nfserrno(host_err);
}
#if defined(CONFIG_NFSD_V4)
diff --git a/fs/pnode.c b/fs/pnode.c
index cbaa998ad625..1d16bb3bdf5e 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -324,6 +324,21 @@ out:
return ret;
}
+static struct mount *find_topper(struct mount *mnt)
+{
+ /* If there is exactly one mount covering mnt completely return it. */
+ struct mount *child;
+
+ if (!list_is_singular(&mnt->mnt_mounts))
+ return NULL;
+
+ child = list_first_entry(&mnt->mnt_mounts, struct mount, mnt_child);
+ if (child->mnt_mountpoint != mnt->mnt.mnt_root)
+ return NULL;
+
+ return child;
+}
+
/*
* return true if the refcount is greater than count
*/
@@ -344,9 +359,8 @@ static inline int do_refcount_check(struct mount *mnt, int count)
*/
int propagate_mount_busy(struct mount *mnt, int refcnt)
{
- struct mount *m, *child;
+ struct mount *m, *child, *topper;
struct mount *parent = mnt->mnt_parent;
- int ret = 0;
if (mnt == parent)
return do_refcount_check(mnt, refcnt);
@@ -361,12 +375,24 @@ int propagate_mount_busy(struct mount *mnt, int refcnt)
for (m = propagation_next(parent, parent); m;
m = propagation_next(m, parent)) {
- child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint);
- if (child && list_empty(&child->mnt_mounts) &&
- (ret = do_refcount_check(child, 1)))
- break;
+ int count = 1;
+ child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint);
+ if (!child)
+ continue;
+
+ /* Is there exactly one mount on the child that covers
+ * it completely whose reference should be ignored?
+ */
+ topper = find_topper(child);
+ if (topper)
+ count += 1;
+ else if (!list_empty(&child->mnt_mounts))
+ continue;
+
+ if (do_refcount_check(child, count))
+ return 1;
}
- return ret;
+ return 0;
}
/*
@@ -383,7 +409,7 @@ void propagate_mount_unlock(struct mount *mnt)
for (m = propagation_next(parent, parent); m;
m = propagation_next(m, parent)) {
- child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint);
+ child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint);
if (child)
child->mnt.mnt_flags &= ~MNT_LOCKED;
}
@@ -401,9 +427,11 @@ static void mark_umount_candidates(struct mount *mnt)
for (m = propagation_next(parent, parent); m;
m = propagation_next(m, parent)) {
- struct mount *child = __lookup_mnt_last(&m->mnt,
+ struct mount *child = __lookup_mnt(&m->mnt,
mnt->mnt_mountpoint);
- if (child && (!IS_MNT_LOCKED(child) || IS_MNT_MARKED(m))) {
+ if (!child || (child->mnt.mnt_flags & MNT_UMOUNT))
+ continue;
+ if (!IS_MNT_LOCKED(child) || IS_MNT_MARKED(m)) {
SET_MNT_MARK(child);
}
}
@@ -422,8 +450,8 @@ static void __propagate_umount(struct mount *mnt)
for (m = propagation_next(parent, parent); m;
m = propagation_next(m, parent)) {
-
- struct mount *child = __lookup_mnt_last(&m->mnt,
+ struct mount *topper;
+ struct mount *child = __lookup_mnt(&m->mnt,
mnt->mnt_mountpoint);
/*
* umount the child only if the child has no children
@@ -432,6 +460,15 @@ static void __propagate_umount(struct mount *mnt)
if (!child || !IS_MNT_MARKED(child))
continue;
CLEAR_MNT_MARK(child);
+
+ /* If there is exactly one mount covering all of child
+ * replace child with that mount.
+ */
+ topper = find_topper(child);
+ if (topper)
+ mnt_change_mountpoint(child->mnt_parent, child->mnt_mp,
+ topper);
+
if (list_empty(&child->mnt_mounts)) {
list_del_init(&child->mnt_child);
child->mnt.mnt_flags |= MNT_UMOUNT;
diff --git a/fs/pnode.h b/fs/pnode.h
index 3cb58c0cdcbc..f41fc9a6c48e 100644
--- a/fs/pnode.h
+++ b/fs/pnode.h
@@ -50,6 +50,8 @@ int get_dominating_id(struct mount *mnt, const struct path *root);
unsigned int mnt_get_count(struct mount *mnt);
void mnt_set_mountpoint(struct mount *, struct mountpoint *,
struct mount *);
+void mnt_change_mountpoint(struct mount *parent, struct mountpoint *mp,
+ struct mount *mnt);
struct mount *copy_tree(struct mount *, struct dentry *, int);
bool is_path_reachable(struct mount *, struct dentry *,
const struct path *root);
diff --git a/fs/splice.c b/fs/splice.c
index 0f77e9682857..8398974e1538 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -211,6 +211,7 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
buf->len = spd->partial[page_nr].len;
buf->private = spd->partial[page_nr].private;
buf->ops = spd->ops;
+ buf->flags = 0;
if (spd->flags & SPLICE_F_GIFT)
buf->flags |= PIPE_BUF_FLAG_GIFT;
diff --git a/include/dt-bindings/clock/msm-clocks-8996.h b/include/dt-bindings/clock/msm-clocks-8996.h
index 22109a6766db..da794841d1eb 100644
--- a/include/dt-bindings/clock/msm-clocks-8996.h
+++ b/include/dt-bindings/clock/msm-clocks-8996.h
@@ -54,6 +54,8 @@
#define clk_ipa_clk 0xfa685cda
#define clk_ln_bb_clk 0x3ab0b36d
#define clk_ln_bb_a_clk 0xc7257ea8
+#define clk_ln_bb_clk_pin 0x1b1c476a
+#define clk_ln_bb_a_clk_pin 0x9cbb5411
#define clk_mcd_ce1_clk 0xbb615d26
#define clk_pnoc_keepalive_a_clk 0xf8f91f0b
#define clk_pnoc_msmbus_clk 0x38b95c77
diff --git a/include/dt-bindings/clock/msm-clocks-hwio-8996.h b/include/dt-bindings/clock/msm-clocks-hwio-8996.h
index 10e25be91752..21dc1e6c55e3 100644
--- a/include/dt-bindings/clock/msm-clocks-hwio-8996.h
+++ b/include/dt-bindings/clock/msm-clocks-hwio-8996.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* 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
@@ -42,6 +42,7 @@
#define RF_CLK1_ID 0x4
#define RF_CLK2_ID 0x5
#define LN_BB_CLK_ID 0x8
+#define LN_BB_CLK_PIN_ID 0x8
#define DIV_CLK1_ID 0xb
#define DIV_CLK2_ID 0xc
#define DIV_CLK3_ID 0xd
diff --git a/include/linux/can/core.h b/include/linux/can/core.h
index a0875001b13c..df08a41d5be5 100644
--- a/include/linux/can/core.h
+++ b/include/linux/can/core.h
@@ -45,10 +45,9 @@ struct can_proto {
extern int can_proto_register(const struct can_proto *cp);
extern void can_proto_unregister(const struct can_proto *cp);
-extern int can_rx_register(struct net_device *dev, canid_t can_id,
- canid_t mask,
- void (*func)(struct sk_buff *, void *),
- void *data, char *ident);
+int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
+ void (*func)(struct sk_buff *, void *),
+ void *data, char *ident, struct sock *sk);
extern void can_rx_unregister(struct net_device *dev, canid_t can_id,
canid_t mask,
diff --git a/include/linux/ceph/osdmap.h b/include/linux/ceph/osdmap.h
index e55c08bc3a96..0abc56140c83 100644
--- a/include/linux/ceph/osdmap.h
+++ b/include/linux/ceph/osdmap.h
@@ -49,7 +49,7 @@ static inline bool ceph_can_shift_osds(struct ceph_pg_pool_info *pool)
case CEPH_POOL_TYPE_EC:
return false;
default:
- BUG_ON(1);
+ BUG();
}
}
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 04a22505edd7..21a0917119ce 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -66,6 +66,7 @@
#define DIAG_IOCTL_PERIPHERAL_BUF_DRAIN 36
#define DIAG_IOCTL_REGISTER_CALLBACK 37
#define DIAG_IOCTL_HDLC_TOGGLE 38
+#define DIAG_IOCTL_QUERY_PD_LOGGING 39
/* PC Tools IDs */
#define APQ8060_TOOLS_ID 4062
diff --git a/include/linux/esoc_client.h b/include/linux/esoc_client.h
index 43c03389ecac..8d13c88eda81 100644
--- a/include/linux/esoc_client.h
+++ b/include/linux/esoc_client.h
@@ -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
@@ -24,6 +24,7 @@
struct esoc_desc {
const char *name;
const char *link;
+ const char *link_info;
void *priv;
};
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index 9364ba71873e..6eb18a6d4e72 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -54,7 +54,8 @@ struct gpio_keys_platform_data {
unsigned int rep:1;
int (*enable)(struct device *dev);
void (*disable)(struct device *dev);
- const char *name;
+ const char *name; /* input device name */
+ bool use_syscore;
};
#endif
diff --git a/include/linux/i2c/i2c-msm-v2.h b/include/linux/i2c/i2c-msm-v2.h
index 54974c02725d..468a1d6fa58d 100644
--- a/include/linux/i2c/i2c-msm-v2.h
+++ b/include/linux/i2c/i2c-msm-v2.h
@@ -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
@@ -552,6 +552,7 @@ struct i2c_msm_xfer {
int msg_cnt;
enum i2c_msm_xfer_mode_id mode_id;
struct completion complete;
+ struct completion rx_complete;
size_t rx_cnt;
size_t tx_cnt;
size_t rx_ovrhd_cnt;
diff --git a/include/linux/input/synaptics_dsx_v2_6.h b/include/linux/input/synaptics_dsx_v2_6.h
deleted file mode 100644
index 5d4bbedb5f1a..000000000000
--- a/include/linux/input/synaptics_dsx_v2_6.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Synaptics DSX touchscreen driver
- *
- * Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
- *
- * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
- * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
- * 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 as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
- * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
- * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
- * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
- * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
- * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
- * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
- * DOLLARS.
- */
-
-#ifndef _SYNAPTICS_DSX_H_
-#define _SYNAPTICS_DSX_H_
-
-#define PLATFORM_DRIVER_NAME "synaptics_dsxv26"
-#define STYLUS_DRIVER_NAME "synaptics_dsxv26_stylus"
-#define ACTIVE_PEN_DRIVER_NAME "synaptics_dsxv26_active_pen"
-#define PROXIMITY_DRIVER_NAME "synaptics_dsxv26_proximity"
-#define GESTURE_DRIVER_NAME "synaptics_dsxv26_gesture"
-#define I2C_DRIVER_NAME "synaptics_dsxv26"
-#define SPI_DRIVER_NAME "synaptics_dsxv26"
-
-/*
- * struct synaptics_dsx_button_map - button map
- * @nbuttons: number of buttons
- * @map: pointer to array of button codes
- */
-struct synaptics_dsx_button_map {
- unsigned char nbuttons;
- unsigned int *map;
-};
-
-/*
- * struct synaptics_dsx_board_data - DSX board data
- * @x_flip: x flip flag
- * @y_flip: y flip flag
- * @swap_axes: swap axes flag
- * @resume_in_workqueue: defer resume function to workqueue
- * @irq_gpio: attention interrupt GPIO
- * @irq_on_state: attention interrupt active state
- * @power_gpio: power switch GPIO
- * @power_on_state: power switch active state
- * @reset_gpio: reset GPIO
- * @reset_on_state: reset active state
- * @max_y_for_2d: maximum y value for 2D area when virtual buttons are present
- * @irq_flags: IRQ flags
- * @i2c_addr: I2C slave address
- * @ub_i2c_addr: microbootloader mode I2C slave address
- * @device_descriptor_addr: HID device descriptor address
- * @panel_x: x-axis resolution of display panel
- * @panel_y: y-axis resolution of display panel
- * @power_delay_ms: delay time to wait after powering up device
- * @reset_delay_ms: delay time to wait after resetting device
- * @reset_active_ms: reset active time
- * @byte_delay_us: delay time between two bytes of SPI data
- * @block_delay_us: delay time between two SPI transfers
- * @pwr_reg_name: pointer to name of regulator for power control
- * @bus_reg_name: pointer to name of regulator for bus pullup control
- * @cap_button_map: pointer to 0D button map
- * @vir_button_map: pointer to virtual button map
- * @resume_in_workqueue: defer resume function to workqueue
- */
-struct synaptics_dsx_board_data {
- bool x_flip;
- bool y_flip;
- bool swap_axes;
- bool resume_in_workqueue;
- int irq_gpio;
- int irq_on_state;
- int power_gpio;
- int power_on_state;
- int reset_gpio;
- int reset_on_state;
- int max_y_for_2d;
- unsigned long irq_flags;
- unsigned short i2c_addr;
- unsigned short ub_i2c_addr;
- unsigned short device_descriptor_addr;
- unsigned int panel_x;
- unsigned int panel_y;
- unsigned int power_delay_ms;
- unsigned int reset_delay_ms;
- unsigned int reset_active_ms;
- unsigned int byte_delay_us;
- unsigned int block_delay_us;
- const char *pwr_reg_name;
- const char *bus_reg_name;
- struct synaptics_dsx_button_map *cap_button_map;
- struct synaptics_dsx_button_map *vir_button_map;
-};
-
-#endif
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h
index d49e26c6cdc7..23e129ef6726 100644
--- a/include/linux/intel-iommu.h
+++ b/include/linux/intel-iommu.h
@@ -153,8 +153,8 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
#define DMA_TLB_GLOBAL_FLUSH (((u64)1) << 60)
#define DMA_TLB_DSI_FLUSH (((u64)2) << 60)
#define DMA_TLB_PSI_FLUSH (((u64)3) << 60)
-#define DMA_TLB_IIRG(type) ((type >> 60) & 7)
-#define DMA_TLB_IAIG(val) (((val) >> 57) & 7)
+#define DMA_TLB_IIRG(type) ((type >> 60) & 3)
+#define DMA_TLB_IAIG(val) (((val) >> 57) & 3)
#define DMA_TLB_READ_DRAIN (((u64)1) << 49)
#define DMA_TLB_WRITE_DRAIN (((u64)1) << 48)
#define DMA_TLB_DID(id) (((u64)((id) & 0xffff)) << 32)
@@ -164,9 +164,9 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
/* INVALID_DESC */
#define DMA_CCMD_INVL_GRANU_OFFSET 61
-#define DMA_ID_TLB_GLOBAL_FLUSH (((u64)1) << 3)
-#define DMA_ID_TLB_DSI_FLUSH (((u64)2) << 3)
-#define DMA_ID_TLB_PSI_FLUSH (((u64)3) << 3)
+#define DMA_ID_TLB_GLOBAL_FLUSH (((u64)1) << 4)
+#define DMA_ID_TLB_DSI_FLUSH (((u64)2) << 4)
+#define DMA_ID_TLB_PSI_FLUSH (((u64)3) << 4)
#define DMA_ID_TLB_READ_DRAIN (((u64)1) << 7)
#define DMA_ID_TLB_WRITE_DRAIN (((u64)1) << 6)
#define DMA_ID_TLB_DID(id) (((u64)((id & 0xffff) << 16)))
@@ -316,8 +316,8 @@ enum {
#define QI_DEV_EIOTLB_SIZE (((u64)1) << 11)
#define QI_DEV_EIOTLB_GLOB(g) ((u64)g)
#define QI_DEV_EIOTLB_PASID(p) (((u64)p) << 32)
-#define QI_DEV_EIOTLB_SID(sid) ((u64)((sid) & 0xffff) << 32)
-#define QI_DEV_EIOTLB_QDEP(qd) (((qd) & 0x1f) << 16)
+#define QI_DEV_EIOTLB_SID(sid) ((u64)((sid) & 0xffff) << 16)
+#define QI_DEV_EIOTLB_QDEP(qd) ((u64)((qd) & 0x1f) << 4)
#define QI_DEV_EIOTLB_MAX_INVS 32
#define QI_PGRP_IDX(idx) (((u64)(idx)) << 55)
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index 3f021dc5da8c..30201b9be7bc 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -83,6 +83,8 @@ struct nd_cmd_desc {
struct nd_interleave_set {
u64 cookie;
+ /* compatibility with initial buggy Linux implementation */
+ u64 altcookie;
};
struct nd_region_desc {
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index c15373894a42..b37dee3acaba 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -355,7 +355,8 @@ static inline int nlm_privileged_requester(const struct svc_rqst *rqstp)
static inline int nlm_compare_locks(const struct file_lock *fl1,
const struct file_lock *fl2)
{
- return fl1->fl_pid == fl2->fl_pid
+ return file_inode(fl1->fl_file) == file_inode(fl2->fl_file)
+ && fl1->fl_pid == fl2->fl_pid
&& fl1->fl_owner == fl2->fl_owner
&& fl1->fl_start == fl2->fl_start
&& fl1->fl_end == fl2->fl_end
diff --git a/include/linux/msm_ext_display.h b/include/linux/msm_ext_display.h
index d9831d7cbb4e..fc53e861eba4 100644
--- a/include/linux/msm_ext_display.h
+++ b/include/linux/msm_ext_display.h
@@ -26,9 +26,13 @@
* interface:
* MSM_EXT_DISP_HPD_AUDIO: audio will be routed to external display
* MSM_EXT_DISP_HPD_VIDEO: video will be routed to external display
+ * MSM_EXT_DISP_HPD_ASYNC_AUDIO: don't wait audio notification once wake it up
+ * MSM_EXT_DISP_HPD_ASYNC_VIDEO: don't wait video notification once wake it up
*/
#define MSM_EXT_DISP_HPD_AUDIO BIT(0)
#define MSM_EXT_DISP_HPD_VIDEO BIT(1)
+#define MSM_EXT_DISP_HPD_ASYNC_AUDIO BIT(2)
+#define MSM_EXT_DISP_HPD_ASYNC_VIDEO BIT(3)
/**
* struct ext_disp_cable_notify - cable notify handler structure
diff --git a/include/linux/msm_mhi.h b/include/linux/msm_mhi.h
index b9fd610f92da..2b50ce59406e 100644
--- a/include/linux/msm_mhi.h
+++ b/include/linux/msm_mhi.h
@@ -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
@@ -13,6 +13,7 @@
#define MSM_MHI_H
#include <linux/types.h>
#include <linux/device.h>
+#include <linux/scatterlist.h>
#define MHI_DMA_MASK 0xFFFFFFFFFFULL
#define MHI_MAX_MTU 0xFFFF
@@ -77,6 +78,7 @@ enum MHI_CB_REASON {
MHI_CB_MHI_ENABLED,
MHI_CB_MHI_SHUTDOWN,
MHI_CB_SYS_ERROR,
+ MHI_CB_RDDM,
};
enum MHI_FLAGS {
@@ -128,16 +130,22 @@ struct __packed bhi_vec_entry {
* @dev: device node points to of_node
* @pdev: pci device node
* @resource: bar memory space and IRQ resources
+ * @support_rddm: this device support ramdump collection
+ * @rddm_size: size of ramdump buffer in bytes to allocate
* @pm_runtime_get: fp for bus masters rpm pm_runtime_get
* @pm_runtime_noidle: fp for bus masters rpm pm_runtime_noidle
+ * @status_cb: fp for MHI status change notifications
* @mhi_dev_ctxt: private data for host
*/
struct mhi_device {
struct device *dev;
struct pci_dev *pci_dev;
struct resource resources[2];
+ bool support_rddm;
+ size_t rddm_size;
int (*pm_runtime_get)(struct pci_dev *pci_dev);
- void (*pm_runtime_noidle)(struct pci_dev *pci_dev);
+ void (*pm_runtime_put_noidle)(struct pci_dev *pci_dev);
+ void (*status_cb)(enum MHI_CB_REASON, void *priv);
struct mhi_device_ctxt *mhi_dev_ctxt;
};
@@ -148,10 +156,16 @@ enum mhi_dev_ctrl {
MHI_DEV_CTRL_RESUME,
MHI_DEV_CTRL_POWER_OFF,
MHI_DEV_CTRL_POWER_ON,
- MHI_DEV_CTRL_RAM_DUMP,
+ MHI_DEV_CTRL_RDDM,
+ MHI_DEV_CTRL_RDDM_KERNEL_PANIC,
MHI_DEV_CTRL_NOTIFY_LINK_ERROR,
};
+enum mhi_rddm_segment {
+ MHI_RDDM_FW_SEGMENT,
+ MHI_RDDM_RD_SEGMENT,
+};
+
/**
* mhi_is_device_ready - Check if MHI is ready to register clients
*
@@ -173,7 +187,7 @@ bool mhi_is_device_ready(const struct device * const dev,
*/
int mhi_register_device(struct mhi_device *mhi_device,
const char *node_name,
- unsigned long user_data);
+ void *user_data);
/**
* mhi_pm_control_device - power management control api
@@ -185,6 +199,15 @@ int mhi_pm_control_device(struct mhi_device *mhi_device,
enum mhi_dev_ctrl ctrl);
/**
+ * mhi_xfer_rddm - transfer rddm segment to bus master
+ * @mhi_device: registered device structure
+ * @seg: scatterlist pointing to segments
+ * @Return: # of segments, 0 if no segment available
+ */
+int mhi_xfer_rddm(struct mhi_device *mhi_device, enum mhi_rddm_segment seg,
+ struct scatterlist **sg_list);
+
+/**
* mhi_deregister_channel - de-register callbacks from MHI
*
* @client_handle: Handle populated by MHI, opaque to client
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 1acd6027f2ea..0a306b431ece 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1399,6 +1399,7 @@ enum netdev_priv_flags {
* @mtu: Interface MTU value
* @type: Interface hardware type
* @hard_header_len: Maximum hardware header length.
+ * @min_header_len: Minimum hardware header length
*
* @needed_headroom: Extra headroom the hardware may need, but not in all
* cases can this be guaranteed
@@ -1619,6 +1620,7 @@ struct net_device {
unsigned int mtu;
unsigned short type;
unsigned short hard_header_len;
+ unsigned short min_header_len;
unsigned short needed_headroom;
unsigned short needed_tailroom;
@@ -2541,6 +2543,8 @@ static inline bool dev_validate_header(const struct net_device *dev,
{
if (likely(len >= dev->hard_header_len))
return true;
+ if (len < dev->min_header_len)
+ return false;
if (capable(CAP_SYS_RAWIO)) {
memset(ll_header + len, 0, dev->hard_header_len - len);
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 1effc355d7d0..864f7f6a0d01 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -217,6 +217,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_DP_DM,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
POWER_SUPPLY_PROP_INPUT_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE,
POWER_SUPPLY_PROP_CURRENT_QNOVO,
POWER_SUPPLY_PROP_VOLTAGE_QNOVO,
POWER_SUPPLY_PROP_RERUN_AICL,
diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
index 4023e3a683d3..7254f4d16176 100644
--- a/include/linux/qpnp/qpnp-revid.h
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -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
@@ -181,6 +181,7 @@
#define PM660L_SUBTYPE 0x1A
#define PM660_SUBTYPE 0x1B
+/* PMI8998 REV_ID */
#define PMI8998_V1P0_REV1 0x00
#define PMI8998_V1P0_REV2 0x00
#define PMI8998_V1P0_REV3 0x00
@@ -196,6 +197,32 @@
#define PMI8998_V2P0_REV3 0x00
#define PMI8998_V2P0_REV4 0x02
+/* PM660 REV_ID */
+#define PM660_V1P0_REV1 0x00
+#define PM660_V1P0_REV2 0x00
+#define PM660_V1P0_REV3 0x00
+#define PM660_V1P0_REV4 0x01
+
+#define PM660_V1P1_REV1 0x00
+#define PM660_V1P1_REV2 0x00
+#define PM660_V1P1_REV3 0x01
+#define PM660_V1P1_REV4 0x01
+
+/* PM660L REV_ID */
+#define PM660L_V1P1_REV1 0x00
+#define PM660L_V1P1_REV2 0x00
+#define PM660L_V1P1_REV3 0x01
+#define PM660L_V1P1_REV4 0x01
+
+/* PMI8998 FAB_ID */
+#define PMI8998_FAB_ID_SMIC 0x11
+#define PMI8998_FAB_ID_GF 0x30
+
+/* PM660 FAB_ID */
+#define PM660_FAB_ID_GF 0x0
+#define PM660_FAB_ID_TSMC 0x2
+#define PM660_FAB_ID_MX 0x3
+
/* PM8005 */
#define PM8005_SUBTYPE 0x18
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index 623fbfce6c67..1e677f95a375 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -5,6 +5,8 @@
#include <linux/compat.h>
+#define MSM_OUTPUT_BUF_CNT 8
+
#ifdef CONFIG_COMPAT
struct msm_cpp_frame_info32_t {
int32_t frame_id;
@@ -26,7 +28,7 @@ struct msm_cpp_frame_info32_t {
uint32_t feature_mask;
uint8_t we_disable;
struct msm_cpp_buffer_info_t input_buffer_info;
- struct msm_cpp_buffer_info_t output_buffer_info[8];
+ struct msm_cpp_buffer_info_t output_buffer_info[MSM_OUTPUT_BUF_CNT];
struct msm_cpp_buffer_info_t duplicate_buffer_info;
struct msm_cpp_buffer_info_t tnr_scratch_buffer_info[2];
uint32_t reserved;
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h
index 3ebb168b9afc..a34b141f125f 100644
--- a/include/net/cipso_ipv4.h
+++ b/include/net/cipso_ipv4.h
@@ -309,6 +309,10 @@ static inline int cipso_v4_validate(const struct sk_buff *skb,
}
for (opt_iter = 6; opt_iter < opt_len;) {
+ if (opt_iter + 1 == opt_len) {
+ err_offset = opt_iter;
+ goto out;
+ }
tag_len = opt[opt_iter + 1];
if ((tag_len == 0) || (tag_len > (opt_len - opt_iter))) {
err_offset = opt_iter + 1;
diff --git a/include/net/cnss_nl.h b/include/net/cnss_nl.h
new file mode 100644
index 000000000000..86c2fccc930e
--- /dev/null
+++ b/include/net/cnss_nl.h
@@ -0,0 +1,100 @@
+/* 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 _NET_CNSS_GENETLINK_H_
+#define _NET_CNSS_GENETLINK_H_
+
+#define CLD80211_MAX_COMMANDS 40
+#define CLD80211_MAX_NL_DATA 4096
+
+/**
+ * enum cld80211_attr - Driver/Application embeds the data in nlmsg with the
+ * help of below attributes
+ *
+ * @CLD80211_ATTR_VENDOR_DATA: Embed all other attributes in this nested
+ * attribute.
+ * @CLD80211_ATTR_DATA: Embed complete data in this attribute
+ *
+ * Any new message in future can be added as another attribute
+ */
+enum cld80211_attr {
+ CLD80211_ATTR_VENDOR_DATA = 1,
+ CLD80211_ATTR_DATA,
+ /* add new attributes above here */
+
+ __CLD80211_ATTR_AFTER_LAST,
+ CLD80211_ATTR_MAX = __CLD80211_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum cld80211_multicast_groups - List of multicast groups supported
+ *
+ * @CLD80211_MCGRP_SVC_MSGS: WLAN service message will be sent to this group.
+ * Ex: Status ind messages
+ * @CLD80211_MCGRP_HOST_LOGS: All logging related messages from driver will be
+ * sent to this multicast group
+ * @CLD80211_MCGRP_FW_LOGS: Firmware logging messages will be sent to this group
+ * @CLD80211_MCGRP_PER_PKT_STATS: Messages related packet stats debugging infra
+ * will be sent to this group
+ * @CLD80211_MCGRP_DIAG_EVENTS: Driver/Firmware status logging diag events will
+ * be sent to this group
+ * @CLD80211_MCGRP_FATAL_EVENTS: Any fatal message generated in driver/firmware
+ * will be sent to this group
+ * @CLD80211_MCGRP_OEM_MSGS: All OEM message will be sent to this group
+ * Ex: LOWI messages
+ */
+enum cld80211_multicast_groups {
+ CLD80211_MCGRP_SVC_MSGS,
+ CLD80211_MCGRP_HOST_LOGS,
+ CLD80211_MCGRP_FW_LOGS,
+ CLD80211_MCGRP_PER_PKT_STATS,
+ CLD80211_MCGRP_DIAG_EVENTS,
+ CLD80211_MCGRP_FATAL_EVENTS,
+ CLD80211_MCGRP_OEM_MSGS,
+};
+
+/**
+ * typedef cld80211_cb - Callback to be called when an nlmsg is received with
+ * the registered cmd_id command from userspace
+ * @data: Payload of the message to be sent to driver
+ * @data_len: Length of the payload
+ * @cb_ctx: callback context to be returned to driver when the callback
+ * is called
+ * @pid: process id of the sender
+ */
+typedef void (*cld80211_cb)(const void *data, int data_len,
+ void *cb_ctx, int pid);
+
+/**
+ * register_cld_cmd_cb() - Allows cld driver to register for commands with
+ * callback
+ * @cmd_id: Command to be registered. Valid range [1, CLD80211_MAX_COMMANDS]
+ * @cb: Callback to be called when an nlmsg is received with cmd_id command
+ * from userspace
+ * @cb_ctx: context provided by driver; Send this as cb_ctx of func()
+ * to driver
+ */
+int register_cld_cmd_cb(u8 cmd_id, cld80211_cb cb, void *cb_ctx);
+
+/**
+ * deregister_cld_cmd_cb() - Allows cld driver to de-register the command it
+ * has already registered
+ * @cmd_id: Command to be deregistered.
+ */
+int deregister_cld_cmd_cb(u8 cmd_id);
+
+/**
+ * cld80211_get_genl_family() - Returns current netlink family context
+ */
+struct genl_family *cld80211_get_genl_family(void);
+
+#endif /* _NET_CNSS_GENETLINK_H_ */
diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h
index 301969552d0a..b43e64d69734 100644
--- a/include/rdma/ib_sa.h
+++ b/include/rdma/ib_sa.h
@@ -138,12 +138,12 @@ struct ib_sa_path_rec {
union ib_gid sgid;
__be16 dlid;
__be16 slid;
- int raw_traffic;
+ u8 raw_traffic;
/* reserved */
__be32 flow_label;
u8 hop_limit;
u8 traffic_class;
- int reversible;
+ u8 reversible;
u8 numb_path;
__be16 pkey;
__be16 qos_class;
@@ -204,7 +204,7 @@ struct ib_sa_mcmember_rec {
u8 hop_limit;
u8 scope;
u8 join_state;
- int proxy_join;
+ u8 proxy_join;
};
/* Service Record Component Mask Sec 15.2.5.14 Ver 1.1 */
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index c37b22101473..5dfc8d01b95c 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -311,6 +311,7 @@ extern void scsi_remove_device(struct scsi_device *);
extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh);
void scsi_attach_vpd(struct scsi_device *sdev);
+extern struct scsi_device *scsi_device_from_queue(struct request_queue *q);
extern int scsi_device_get(struct scsi_device *);
extern void scsi_device_put(struct scsi_device *);
extern struct scsi_device *scsi_device_lookup(struct Scsi_Host *,
diff --git a/include/soc/at91/at91sam9_ddrsdr.h b/include/soc/at91/at91sam9_ddrsdr.h
index dc10c52e0e91..393362bdb860 100644
--- a/include/soc/at91/at91sam9_ddrsdr.h
+++ b/include/soc/at91/at91sam9_ddrsdr.h
@@ -81,6 +81,7 @@
#define AT91_DDRSDRC_LPCB_POWER_DOWN 2
#define AT91_DDRSDRC_LPCB_DEEP_POWER_DOWN 3
#define AT91_DDRSDRC_CLKFR (1 << 2) /* Clock Frozen */
+#define AT91_DDRSDRC_LPDDR2_PWOFF (1 << 3) /* LPDDR Power Off */
#define AT91_DDRSDRC_PASR (7 << 4) /* Partial Array Self Refresh */
#define AT91_DDRSDRC_TCSR (3 << 8) /* Temperature Compensated Self Refresh */
#define AT91_DDRSDRC_DS (3 << 10) /* Drive Strength */
@@ -96,7 +97,9 @@
#define AT91_DDRSDRC_MD_SDR 0
#define AT91_DDRSDRC_MD_LOW_POWER_SDR 1
#define AT91_DDRSDRC_MD_LOW_POWER_DDR 3
+#define AT91_DDRSDRC_MD_LPDDR3 5
#define AT91_DDRSDRC_MD_DDR2 6 /* [SAM9 Only] */
+#define AT91_DDRSDRC_MD_LPDDR2 7
#define AT91_DDRSDRC_DBW (1 << 4) /* Data Bus Width */
#define AT91_DDRSDRC_DBW_32BITS (0 << 4)
#define AT91_DDRSDRC_DBW_16BITS (1 << 4)
diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h
index 731fa6970b95..7ef984afc442 100644
--- a/include/soc/qcom/icnss.h
+++ b/include/soc/qcom/icnss.h
@@ -20,6 +20,11 @@
enum icnss_uevent {
ICNSS_UEVENT_FW_READY,
ICNSS_UEVENT_FW_CRASHED,
+ ICNSS_UEVENT_FW_DOWN,
+};
+
+struct icnss_uevent_fw_down_data {
+ bool crashed;
};
struct icnss_uevent_data {
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 06c273252484..a5ba1496eef7 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -443,6 +443,11 @@ struct adm_param_data_v5 {
*/
} __packed;
+#define ASM_STREAM_CMD_REGISTER_PP_EVENTS 0x00013213
+#define ASM_STREAM_PP_EVENT 0x00013214
+#define DSP_STREAM_CMD "ADSP Stream Cmd"
+#define DSP_STREAM_CALLBACK "ADSP Stream Callback Event"
+
/* set customized mixing on matrix mixer */
#define ADM_CMD_SET_PSPD_MTMX_STRTR_PARAMS_V5 0x00010344
struct adm_cmd_set_pspd_mtmx_strtr_params_v5 {
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index d077827647b5..29707b26644a 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -618,6 +618,9 @@ int q6asm_get_session_time_legacy(struct audio_client *ac, uint64_t *tstamp);
int q6asm_send_audio_effects_params(struct audio_client *ac, char *params,
uint32_t params_length);
+int q6asm_send_stream_cmd(struct audio_client *ac, uint32_t opcode,
+ void *param, uint32_t params_length);
+
/* Client can set the IO mode to either AIO/SIO mode */
int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode);
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 6afc6f388edf..ed66414b91f0 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -544,6 +544,7 @@ struct se_node_acl {
/* Used to signal demo mode created ACL, disabled by default */
bool dynamic_node_acl;
bool acl_stop:1;
+ bool dynamic_stop;
u32 queue_depth;
u32 acl_index;
enum target_prot_type saved_prot_type;
@@ -739,6 +740,7 @@ struct se_lun {
struct config_group lun_group;
struct se_port_stat_grps port_stat_grps;
struct completion lun_ref_comp;
+ struct completion lun_shutdown_comp;
struct percpu_ref lun_ref;
struct list_head lun_dev_link;
struct hlist_node link;
diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h
index ce9ea736f1d7..97069ecabe49 100644
--- a/include/target/target_core_fabric.h
+++ b/include/target/target_core_fabric.h
@@ -168,6 +168,8 @@ void core_allocate_nexus_loss_ua(struct se_node_acl *acl);
struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg,
unsigned char *);
+bool target_tpg_has_node_acl(struct se_portal_group *tpg,
+ const char *);
struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *,
unsigned char *);
int core_tpg_set_initiator_node_queue_depth(struct se_portal_group *,
diff --git a/include/trace/events/syscalls.h b/include/trace/events/syscalls.h
index 14e49c798135..b35533b94277 100644
--- a/include/trace/events/syscalls.h
+++ b/include/trace/events/syscalls.h
@@ -1,5 +1,6 @@
#undef TRACE_SYSTEM
#define TRACE_SYSTEM raw_syscalls
+#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE syscalls
#if !defined(_TRACE_EVENTS_SYSCALLS_H) || defined(TRACE_HEADER_MULTI_READ)
diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index 99fe34d25fc5..8baf2bf6df2e 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -253,6 +253,66 @@ struct drm_msm_event_resp {
__u8 data[];
};
+#define MSM_COUNTER_GROUP_CP 0
+#define MSM_COUNTER_GROUP_RBBM 1
+#define MSM_COUNTER_GROUP_PC 2
+#define MSM_COUNTER_GROUP_VFD 3
+#define MSM_COUNTER_GROUP_HLSQ 4
+#define MSM_COUNTER_GROUP_VPC 5
+#define MSM_COUNTER_GROUP_TSE 6
+#define MSM_COUNTER_GROUP_RAS 7
+#define MSM_COUNTER_GROUP_UCHE 8
+#define MSM_COUNTER_GROUP_TP 9
+#define MSM_COUNTER_GROUP_SP 10
+#define MSM_COUNTER_GROUP_RB 11
+#define MSM_COUNTER_GROUP_VBIF 12
+#define MSM_COUNTER_GROUP_VBIF_PWR 13
+#define MSM_COUNTER_GROUP_VSC 23
+#define MSM_COUNTER_GROUP_CCU 24
+#define MSM_COUNTER_GROUP_LRZ 25
+#define MSM_COUNTER_GROUP_CMP 26
+#define MSM_COUNTER_GROUP_ALWAYSON 27
+#define MSM_COUNTER_GROUP_SP_PWR 28
+#define MSM_COUNTER_GROUP_TP_PWR 29
+#define MSM_COUNTER_GROUP_RB_PWR 30
+#define MSM_COUNTER_GROUP_CCU_PWR 31
+#define MSM_COUNTER_GROUP_UCHE_PWR 32
+#define MSM_COUNTER_GROUP_CP_PWR 33
+#define MSM_COUNTER_GROUP_GPMU_PWR 34
+#define MSM_COUNTER_GROUP_ALWAYSON_PWR 35
+
+/**
+ * struct drm_msm_counter - allocate or release a GPU performance counter
+ * @groupid: The group ID of the counter to get/put
+ * @counterid: For GET returns the counterid that was assigned. For PUT
+ * release the counter identified by groupid/counterid
+ * @countable: For GET the countable for the counter
+ */
+struct drm_msm_counter {
+ __u32 groupid;
+ int counterid;
+ __u32 countable;
+ __u32 counter_lo;
+ __u32 counter_hi;
+};
+
+struct drm_msm_counter_read_op {
+ __u64 value;
+ __u32 groupid;
+ int counterid;
+};
+
+/**
+ * struct drm_msm_counter_read - Read a number of GPU performance counters
+ * ops: Pointer to the list of struct drm_msm_counter_read_op operations
+ * nr_ops: Number of operations in the list
+ */
+struct drm_msm_counter_read {
+ __u64 __user ops;
+ __u32 nr_ops;
+};
+
+
#define DRM_MSM_GET_PARAM 0x00
/* placeholder:
#define DRM_MSM_SET_PARAM 0x01
@@ -267,6 +327,9 @@ struct drm_msm_event_resp {
#define DRM_SDE_WB_CONFIG 0x40
#define DRM_MSM_REGISTER_EVENT 0x41
#define DRM_MSM_DEREGISTER_EVENT 0x42
+#define DRM_MSM_COUNTER_GET 0x43
+#define DRM_MSM_COUNTER_PUT 0x44
+#define DRM_MSM_COUNTER_READ 0x45
/**
* Currently DRM framework supports only VSYNC event.
@@ -289,4 +352,12 @@ struct drm_msm_event_resp {
DRM_MSM_REGISTER_EVENT), struct drm_msm_event_req)
#define DRM_IOCTL_MSM_DEREGISTER_EVENT DRM_IOW((DRM_COMMAND_BASE + \
DRM_MSM_DEREGISTER_EVENT), struct drm_msm_event_req)
+#define DRM_IOCTL_MSM_COUNTER_GET \
+ DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_COUNTER_GET, struct drm_msm_counter)
+#define DRM_IOCTL_MSM_COUNTER_PUT \
+ DRM_IOW(DRM_COMMAND_BASE + DRM_MSM_COUNTER_PUT, struct drm_msm_counter)
+#define DRM_IOCTL_MSM_COUNTER_READ \
+ DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_COUNTER_READ, \
+ struct drm_msm_counter_read)
+
#endif /* __MSM_DRM_H__ */
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 748b7c277a3c..06f2ca2b0a95 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -402,6 +402,7 @@ header-y += reiserfs_xattr.h
header-y += resource.h
header-y += rfkill.h
header-y += rmnet_data.h
+header-y += rmnet.h
header-y += romfs_fs.h
header-y += rose.h
header-y += route.h
diff --git a/include/uapi/linux/esoc_ctrl.h b/include/uapi/linux/esoc_ctrl.h
index 1e70483e7352..57266ed29fb3 100644
--- a/include/uapi/linux/esoc_ctrl.h
+++ b/include/uapi/linux/esoc_ctrl.h
@@ -3,11 +3,11 @@
#define ESOC_CODE 0xCC
-#define ESOC_CMD_EXE _IOW(ESOC_CODE, 1, u32)
-#define ESOC_WAIT_FOR_REQ _IOR(ESOC_CODE, 2, u32)
-#define ESOC_NOTIFY _IOW(ESOC_CODE, 3, u32)
-#define ESOC_GET_STATUS _IOR(ESOC_CODE, 4, u32)
-#define ESOC_WAIT_FOR_CRASH _IOR(ESOC_CODE, 6, u32)
+#define ESOC_CMD_EXE _IOW(ESOC_CODE, 1, unsigned int)
+#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_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)
diff --git a/include/uapi/linux/rmnet.h b/include/uapi/linux/rmnet.h
new file mode 100644
index 000000000000..698b868076f4
--- /dev/null
+++ b/include/uapi/linux/rmnet.h
@@ -0,0 +1,213 @@
+/* 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
+ * 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.
+ *
+ * RMNET Data configuration specification
+ */
+
+#ifndef _RMNET_DATA_H_
+#define _RMNET_DATA_H_
+
+/* Netlink API */
+#define RMNET_NETLINK_PROTO 31
+#define RMNET_MAX_STR_LEN 16
+#define RMNET_NL_DATA_MAX_LEN 64
+
+#define RMNET_NETLINK_MSG_COMMAND 0
+#define RMNET_NETLINK_MSG_RETURNCODE 1
+#define RMNET_NETLINK_MSG_RETURNDATA 2
+
+/* Constants */
+#define RMNET_EGRESS_FORMAT__RESERVED__ (1<<0)
+#define RMNET_EGRESS_FORMAT_MAP (1<<1)
+#define RMNET_EGRESS_FORMAT_AGGREGATION (1<<2)
+#define RMNET_EGRESS_FORMAT_MUXING (1<<3)
+#define RMNET_EGRESS_FORMAT_MAP_CKSUMV3 (1<<4)
+#define RMNET_EGRESS_FORMAT_MAP_CKSUMV4 (1<<5)
+
+#define RMNET_INGRESS_FIX_ETHERNET (1<<0)
+#define RMNET_INGRESS_FORMAT_MAP (1<<1)
+#define RMNET_INGRESS_FORMAT_DEAGGREGATION (1<<2)
+#define RMNET_INGRESS_FORMAT_DEMUXING (1<<3)
+#define RMNET_INGRESS_FORMAT_MAP_COMMANDS (1<<4)
+#define RMNET_INGRESS_FORMAT_MAP_CKSUMV3 (1<<5)
+#define RMNET_INGRESS_FORMAT_MAP_CKSUMV4 (1<<6)
+
+struct rmnet_nl_msg_s {
+ __be16 reserved;
+ __be16 message_type;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ __u16 crd:2,
+ reserved2:14;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ __u16 reserved2:14,
+ crd:2;
+#endif
+ union {
+ __be16 arg_length;
+ __be16 return_code;
+ };
+ union {
+ __u8 data[RMNET_NL_DATA_MAX_LEN];
+ struct {
+ __u8 dev[RMNET_MAX_STR_LEN];
+ __be32 flags;
+ __be16 agg_size;
+ __be16 agg_count;
+ __u8 tail_spacing;
+ } data_format;
+ struct {
+ __u8 dev[RMNET_MAX_STR_LEN];
+ __be32 ep_id;
+ __u8 operating_mode;
+ __u8 next_dev[RMNET_MAX_STR_LEN];
+ } local_ep_config;
+ struct {
+ __be32 id;
+ __u8 vnd_name[RMNET_MAX_STR_LEN];
+ } vnd;
+ };
+};
+
+/* RMNET_NETLINK_ASSOCIATE_NETWORK_DEVICE - Register RMNET data driver
+ * on a particular device.
+ * Args: char[] dev_name: Null terminated ASCII string, max length: 15
+ * Returns: status code
+ */
+#define RMNET_NETLINK_ASSOCIATE_NETWORK_DEVICE 0
+
+/* RMNET_NETLINK_UNASSOCIATE_NETWORK_DEVICE - Unregister RMNET data
+ * driver on a particular
+ * device.
+ * Args: char[] dev_name: Null terminated ASCII string, max length: 15
+ * Returns: status code
+ */
+#define RMNET_NETLINK_UNASSOCIATE_NETWORK_DEVICE 1
+
+/* RMNET_NETLINK_GET_NETWORK_DEVICE_ASSOCIATED - Get if RMNET data
+ * driver is registered on a
+ * particular device.
+ * Args: char[] dev_name: Null terminated ASCII string, max length: 15
+ * Returns: 1 if registered, 0 if not
+ */
+#define RMNET_NETLINK_GET_NETWORK_DEVICE_ASSOCIATED 2
+
+/* RMNET_NETLINK_SET_LINK_EGRESS_DATA_FORMAT - Sets the egress data
+ * format for a particular
+ * link.
+ * Args: __be32 egress_flags
+ * char[] dev_name: Null terminated ASCII string, max length: 15
+ * Returns: status code
+ */
+#define RMNET_NETLINK_SET_LINK_EGRESS_DATA_FORMAT 3
+
+/* RMNET_NETLINK_GET_LINK_EGRESS_DATA_FORMAT - Gets the egress data
+ * format for a particular
+ * link.
+ * Args: char[] dev_name: Null terminated ASCII string, max length: 15
+ * Returns: 4-bytes data: __be32 egress_flags
+ */
+#define RMNET_NETLINK_GET_LINK_EGRESS_DATA_FORMAT 4
+
+/* RMNET_NETLINK_SET_LINK_INGRESS_DATA_FORMAT - Sets the ingress data
+ * format for a particular
+ * link.
+ * Args: __be32 ingress_flags
+ * char[] dev_name: Null terminated ASCII string, max length: 15
+ * Returns: status code
+ */
+#define RMNET_NETLINK_SET_LINK_INGRESS_DATA_FORMAT 5
+
+/* RMNET_NETLINK_GET_LINK_INGRESS_DATA_FORMAT - Gets the ingress data
+ * format for a particular
+ * link.
+ * Args: char[] dev_name: Null terminated ASCII string, max length: 15
+ * Returns: 4-bytes data: __be32 ingress_flags
+ */
+#define RMNET_NETLINK_GET_LINK_INGRESS_DATA_FORMAT 6
+
+/* RMNET_NETLINK_SET_LOGICAL_EP_CONFIG - Sets the logical endpoint
+ * configuration for a particular
+ * link.
+ * Args: char[] dev_name: Null terminated ASCII string, max length: 15
+ * __be32 logical_ep_id, valid values are -1 through 31
+ * __u8 rmnet_mode: one of none, vnd, bridged
+ * char[] egress_dev_name: Egress device if operating in bridge mode
+ * Returns: status code
+ */
+#define RMNET_NETLINK_SET_LOGICAL_EP_CONFIG 7
+
+/* RMNET_NETLINK_UNSET_LOGICAL_EP_CONFIG - Un-sets the logical endpoint
+ * configuration for a particular
+ * link.
+ * Args: char[] dev_name: Null terminated ASCII string, max length: 15
+ * __be32 logical_ep_id, valid values are -1 through 31
+ * Returns: status code
+ */
+#define RMNET_NETLINK_UNSET_LOGICAL_EP_CONFIG 8
+
+/* RMNET_NETLINK_GET_LOGICAL_EP_CONFIG - Gets the logical endpoint
+ * configuration for a particular
+ * link.
+ * Args: char[] dev_name: Null terminated ASCII string, max length: 15
+ * __be32 logical_ep_id, valid values are -1 through 31
+ * Returns: __u8 rmnet_mode: one of none, vnd, bridged
+ * char[] egress_dev_name: Egress device
+ */
+#define RMNET_NETLINK_GET_LOGICAL_EP_CONFIG 9
+
+/* RMNET_NETLINK_NEW_VND - Creates a new virtual network device node
+ * Args: __be32 node number
+ * Returns: status code
+ */
+#define RMNET_NETLINK_NEW_VND 10
+
+/* RMNET_NETLINK_NEW_VND_WITH_PREFIX - Creates a new virtual network
+ * device node with the specified
+ * prefix for the device name
+ * Args: __be32 node number
+ * char[] vnd_name - Use as prefix
+ * Returns: status code
+ */
+#define RMNET_NETLINK_NEW_VND_WITH_PREFIX 11
+
+/* RMNET_NETLINK_GET_VND_NAME - Gets the string name of a VND from ID
+ * Args: __be32 node number
+ * Returns: char[] vnd_name
+ */
+#define RMNET_NETLINK_GET_VND_NAME 12
+
+/* RMNET_NETLINK_FREE_VND - Removes virtual network device node
+ * Args: __be32 node number
+ * Returns: status code
+ */
+#define RMNET_NETLINK_FREE_VND 13
+
+/* Pass the frame up the stack with no modifications to skb->dev */
+#define RMNET_EPMODE_NONE 0
+/* Replace skb->dev to a virtual rmnet device and pass up the stack */
+#define RMNET_EPMODE_VND 1
+/* Pass the frame directly to another device with dev_queue_xmit(). */
+#define RMNET_EPMODE_BRIDGE 2
+/* Must be the last item in the list */
+#define RMNET_EPMODE_LENGTH 3
+
+#define RMNET_CONFIG_OK 0
+#define RMNET_CONFIG_UNKNOWN_MESSAGE 1
+#define RMNET_CONFIG_UNKNOWN_ERROR 2
+#define RMNET_CONFIG_NOMEM 3
+#define RMNET_CONFIG_DEVICE_IN_USE 4
+#define RMNET_CONFIG_INVALID_REQUEST 5
+#define RMNET_CONFIG_NO_SUCH_DEVICE 6
+#define RMNET_CONFIG_BAD_ARGUMENTS 7
+#define RMNET_CONFIG_BAD_EGRESS_DEVICE 8
+#define RMNET_CONFIG_TC_HANDLE_FULL 9
+
+#endif /* _RMNET_DATA_H_ */
diff --git a/include/uapi/linux/rmnet_data.h b/include/uapi/linux/rmnet_data.h
index 8cfe0270ef4f..7ddfa20cec32 100644
--- a/include/uapi/linux/rmnet_data.h
+++ b/include/uapi/linux/rmnet_data.h
@@ -1,5 +1,5 @@
/*
- * 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
@@ -223,8 +223,19 @@ enum rmnet_netlink_message_types_e {
* uint32_t MAP Flow Handle
* Returns: status code
*/
- RMNET_NETLINK_DEL_VND_TC_FLOW
+ RMNET_NETLINK_DEL_VND_TC_FLOW,
+
+ /*
+ * RMNET_NETLINK_NEW_VND_WITH_NAME - Creates a new virtual network
+ * device node with the specified
+ * device name
+ * Args: int32_t node number
+ * char[] vnd_name - Use as name
+ * Returns: status code
+ */
+ RMNET_NETLINK_NEW_VND_WITH_NAME
};
+#define RMNET_NETLINK_NEW_VND_WITH_NAME RMNET_NETLINK_NEW_VND_WITH_NAME
enum rmnet_config_endpoint_modes_e {
/* Pass the frame up the stack with no modifications to skb->dev */
diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h
index f59f034a72b9..13bee7a56a0e 100644
--- a/include/uapi/media/msm_media_info.h
+++ b/include/uapi/media/msm_media_info.h
@@ -222,7 +222,7 @@ enum color_fmts {
* Y_Stride = align(Width, 128)
* UV_Stride = align(Width, 128)
* Y_Scanlines = align(Height, 32)
- * UV_Scanlines = align((Height + 96)/2, 16)
+ * UV_Scanlines = align(Height/2, 16)
* Y_UBWC_Plane_size = align(Y_Stride * Y_Scanlines, 4096)
* UV_UBWC_Plane_size = align(UV_Stride * UV_Scanlines, 4096)
* Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64)
@@ -235,7 +235,7 @@ enum color_fmts {
*
* Total size = align( Y_UBWC_Plane_size + UV_UBWC_Plane_size +
* Y_Meta_Plane_size + UV_Meta_Plane_size
- * + Extradata), 4096)
+ * + max(Extradata, Y_Stride * 64), 4096)
*/
COLOR_FMT_NV12_UBWC,
/* Venus NV12 10-bit UBWC:
@@ -311,7 +311,7 @@ enum color_fmts {
* Y_Stride = align(Width * 4/3, 128)
* UV_Stride = align(Width * 4/3, 128)
* Y_Scanlines = align(Height, 32)
- * UV_Scanlines = align((Height + 96)/2, 16)
+ * UV_Scanlines = align(Height/2, 16)
* Y_UBWC_Plane_Size = align(Y_Stride * Y_Scanlines, 4096)
* UV_UBWC_Plane_Size = align(UV_Stride * UV_Scanlines, 4096)
* Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64)
@@ -324,7 +324,7 @@ enum color_fmts {
*
* Total size = align(Y_UBWC_Plane_size + UV_UBWC_Plane_size +
* Y_Meta_Plane_size + UV_Meta_Plane_size
- * + Extradata), 4096)
+ * + max(Extradata, Y_Stride * 64), 4096)
*/
COLOR_FMT_NV12_BPP10_UBWC,
/* Venus RGBA8888 format:
@@ -970,7 +970,6 @@ static inline unsigned int VENUS_BUFFER_SIZE(
break;
case COLOR_FMT_NV12_UBWC:
case COLOR_FMT_NV12_BPP10_UBWC:
- uv_sclines = VENUS_UV_SCANLINES(color_fmt, height + 96);
y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096);
y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width);
@@ -983,7 +982,8 @@ static inline unsigned int VENUS_BUFFER_SIZE(
uv_meta_scanlines, 4096);
size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane +
- uv_meta_plane + extra_size;
+ uv_meta_plane + MSM_MEDIA_MAX(extra_size,
+ 64 * y_stride);
size = MSM_MEDIA_ALIGN(size, 4096);
break;
case COLOR_FMT_P010_UBWC:
diff --git a/ipc/shm.c b/ipc/shm.c
index 88a6f1e78066..09267be8d27b 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -1083,8 +1083,8 @@ out_unlock1:
* "raddr" thing points to kernel space, and there has to be a wrapper around
* this.
*/
-long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
- unsigned long shmlba)
+long do_shmat(int shmid, char __user *shmaddr, int shmflg,
+ ulong *raddr, unsigned long shmlba)
{
struct shmid_kernel *shp;
unsigned long addr;
@@ -1105,8 +1105,13 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
goto out;
else if ((addr = (ulong)shmaddr)) {
if (addr & (shmlba - 1)) {
- if (shmflg & SHM_RND)
- addr &= ~(shmlba - 1); /* round down */
+ /*
+ * Round down to the nearest multiple of shmlba.
+ * For sane do_mmap_pgoff() parameters, avoid
+ * round downs that trigger nil-page and MAP_FIXED.
+ */
+ if ((shmflg & SHM_RND) && addr >= shmlba)
+ addr &= ~(shmlba - 1);
else
#ifndef __ARCH_FORCE_SHMLBA
if (addr & ~PAGE_MASK)
diff --git a/kernel/futex.c b/kernel/futex.c
index e8af73cc51a7..beb042dcc332 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -3199,4 +3199,4 @@ static int __init futex_init(void)
return 0;
}
-__initcall(futex_init);
+core_initcall(futex_init);
diff --git a/kernel/membarrier.c b/kernel/membarrier.c
index 536c727a56e9..9f9284f37f8d 100644
--- a/kernel/membarrier.c
+++ b/kernel/membarrier.c
@@ -16,6 +16,7 @@
#include <linux/syscalls.h>
#include <linux/membarrier.h>
+#include <linux/tick.h>
/*
* Bitmask made from a "or" of all commands within enum membarrier_cmd,
@@ -51,6 +52,9 @@
*/
SYSCALL_DEFINE2(membarrier, int, cmd, int, flags)
{
+ /* MEMBARRIER_CMD_SHARED is not compatible with nohz_full. */
+ if (tick_nohz_full_enabled())
+ return -ENOSYS;
if (unlikely(flags))
return -EINVAL;
switch (cmd) {
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 7b884dc55bd0..9fcb521fab0e 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1440,7 +1440,7 @@ static void call_console_drivers(int level,
{
struct console *con;
- trace_console(text, len);
+ trace_console_rcuidle(text, len);
if (level >= console_loglevel && !ignore_loglevel)
return;
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 312ffdad034a..1017a3f77391 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -88,6 +88,7 @@
#include "sched.h"
#include "../workqueue_internal.h"
#include "../smpboot.h"
+#include "../time/tick-internal.h"
#define CREATE_TRACE_POINTS
#include <trace/events/sched.h>
@@ -3260,7 +3261,8 @@ void scheduler_tick(void)
if (curr->sched_class == &fair_sched_class)
check_for_migration(rq, curr);
- core_ctl_check(wallclock);
+ if (cpu == tick_do_timer_cpu)
+ core_ctl_check(wallclock);
}
#ifdef CONFIG_NO_HZ_FULL
diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c
index 983159cc0646..1dde338d30f2 100644
--- a/kernel/sched/core_ctl.c
+++ b/kernel/sched/core_ctl.c
@@ -653,6 +653,9 @@ int core_ctl_set_boost(bool boost)
int ret = 0;
bool boost_state_changed = false;
+ if (unlikely(!initialized))
+ return 0;
+
spin_lock_irqsave(&state_lock, flags);
for_each_cluster(cluster, index) {
if (cluster->is_big_cluster) {
@@ -931,6 +934,42 @@ static struct notifier_block __refdata cpu_notifier = {
/* ============================ init code ============================== */
+static cpumask_var_t core_ctl_disable_cpumask;
+static bool core_ctl_disable_cpumask_present;
+
+static int __init core_ctl_disable_setup(char *str)
+{
+ if (!*str)
+ return -EINVAL;
+
+ alloc_bootmem_cpumask_var(&core_ctl_disable_cpumask);
+
+ if (cpulist_parse(str, core_ctl_disable_cpumask) < 0) {
+ free_bootmem_cpumask_var(core_ctl_disable_cpumask);
+ return -EINVAL;
+ }
+
+ core_ctl_disable_cpumask_present = true;
+ pr_info("disable_cpumask=%*pbl\n",
+ cpumask_pr_args(core_ctl_disable_cpumask));
+
+ return 0;
+}
+early_param("core_ctl_disable_cpumask", core_ctl_disable_setup);
+
+static bool should_skip(const struct cpumask *mask)
+{
+ if (!core_ctl_disable_cpumask_present)
+ return false;
+
+ /*
+ * We operate on a cluster basis. Disable the core_ctl for
+ * a cluster, if all of it's cpus are specified in
+ * core_ctl_disable_cpumask
+ */
+ return cpumask_subset(mask, core_ctl_disable_cpumask);
+}
+
static struct cluster_data *find_cluster_by_first_cpu(unsigned int first_cpu)
{
unsigned int i;
@@ -952,6 +991,9 @@ static int cluster_init(const struct cpumask *mask)
unsigned int cpu;
struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+ if (should_skip(mask))
+ return 0;
+
if (find_cluster_by_first_cpu(first_cpu))
return 0;
@@ -1052,6 +1094,9 @@ static int __init core_ctl_init(void)
{
unsigned int cpu;
+ if (should_skip(cpu_possible_mask))
+ return 0;
+
core_ctl_check_interval = (rq_avg_period_ms - RQ_AVG_TOLERANCE)
* NSEC_PER_MSEC;
diff --git a/kernel/trace/ipc_logging.c b/kernel/trace/ipc_logging.c
index 2c3e0998d400..ed29c38cd7fb 100644
--- a/kernel/trace/ipc_logging.c
+++ b/kernel/trace/ipc_logging.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -507,8 +507,8 @@ int ipc_log_string(void *ilctxt, const char *fmt, ...)
tsv_qtimer_write(&ectxt);
avail_size = (MAX_MSG_SIZE - (ectxt.offset + hdr_size));
va_start(arg_list, fmt);
- data_size = vsnprintf((ectxt.buff + ectxt.offset + hdr_size),
- avail_size, fmt, arg_list);
+ data_size = vscnprintf((ectxt.buff + ectxt.offset + hdr_size),
+ avail_size, fmt, arg_list);
va_end(arg_list);
tsv_write_header(&ectxt, TSV_TYPE_BYTE_ARRAY, data_size);
ectxt.offset += data_size;
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 9ef80bf441b3..a988d4ef39da 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -757,15 +757,20 @@ static int cgwb_bdi_init(struct backing_dev_info *bdi)
if (!bdi->wb_congested)
return -ENOMEM;
+ atomic_set(&bdi->wb_congested->refcnt, 1);
+
err = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL);
if (err) {
- kfree(bdi->wb_congested);
+ wb_congested_put(bdi->wb_congested);
return err;
}
return 0;
}
-static void cgwb_bdi_destroy(struct backing_dev_info *bdi) { }
+static void cgwb_bdi_destroy(struct backing_dev_info *bdi)
+{
+ wb_congested_put(bdi->wb_congested);
+}
#endif /* CONFIG_CGROUP_WRITEBACK */
diff --git a/mm/filemap.c b/mm/filemap.c
index 33be70a2ded3..8b2cf0f6a529 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -867,9 +867,12 @@ void page_endio(struct page *page, int rw, int err)
unlock_page(page);
} else { /* rw == WRITE */
if (err) {
+ struct address_space *mapping;
+
SetPageError(page);
- if (page->mapping)
- mapping_set_error(page->mapping, err);
+ mapping = page_mapping(page);
+ if (mapping)
+ mapping_set_error(mapping, err);
}
end_page_writeback(page);
}
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 43eefe9d834c..e25b93a4267d 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -4150,24 +4150,6 @@ static void mem_cgroup_id_get_many(struct mem_cgroup *memcg, unsigned int n)
atomic_add(n, &memcg->id.ref);
}
-static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg)
-{
- while (!atomic_inc_not_zero(&memcg->id.ref)) {
- /*
- * The root cgroup cannot be destroyed, so it's refcount must
- * always be >= 1.
- */
- if (WARN_ON_ONCE(memcg == root_mem_cgroup)) {
- VM_BUG_ON(1);
- break;
- }
- memcg = parent_mem_cgroup(memcg);
- if (!memcg)
- memcg = root_mem_cgroup;
- }
- return memcg;
-}
-
static void mem_cgroup_id_put_many(struct mem_cgroup *memcg, unsigned int n)
{
if (atomic_sub_and_test(n, &memcg->id.ref)) {
@@ -5751,6 +5733,24 @@ static int __init mem_cgroup_init(void)
subsys_initcall(mem_cgroup_init);
#ifdef CONFIG_MEMCG_SWAP
+static struct mem_cgroup *mem_cgroup_id_get_online(struct mem_cgroup *memcg)
+{
+ while (!atomic_inc_not_zero(&memcg->id.ref)) {
+ /*
+ * The root cgroup cannot be destroyed, so it's refcount must
+ * always be >= 1.
+ */
+ if (WARN_ON_ONCE(memcg == root_mem_cgroup)) {
+ VM_BUG_ON(1);
+ break;
+ }
+ memcg = parent_mem_cgroup(memcg);
+ if (!memcg)
+ memcg = root_mem_cgroup;
+ }
+ return memcg;
+}
+
/**
* mem_cgroup_swapout - transfer a memsw charge to swap
* @page: page whose memsw charge to transfer
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index fbed8bb17388..28f60d9ea074 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2569,7 +2569,7 @@ static bool zone_local(struct zone *local_zone, struct zone *zone)
static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone)
{
- return node_distance(zone_to_nid(local_zone), zone_to_nid(zone)) <
+ return node_distance(zone_to_nid(local_zone), zone_to_nid(zone)) <=
RECLAIM_DISTANCE;
}
#else /* CONFIG_NUMA */
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 166d436196c1..928f58064098 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -445,6 +445,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
* @func: callback function on filter match
* @data: returned parameter for callback function
* @ident: string for calling module identification
+ * @sk: socket pointer (might be NULL)
*
* Description:
* Invokes the callback function with the received sk_buff and the given
@@ -468,7 +469,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
*/
int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
void (*func)(struct sk_buff *, void *), void *data,
- char *ident)
+ char *ident, struct sock *sk)
{
struct receiver *r;
struct hlist_head *rl;
@@ -496,6 +497,7 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
r->func = func;
r->data = data;
r->ident = ident;
+ r->sk = sk;
hlist_add_head_rcu(&r->list, rl);
d->entries++;
@@ -520,8 +522,11 @@ EXPORT_SYMBOL(can_rx_register);
static void can_rx_delete_receiver(struct rcu_head *rp)
{
struct receiver *r = container_of(rp, struct receiver, rcu);
+ struct sock *sk = r->sk;
kmem_cache_free(rcv_cache, r);
+ if (sk)
+ sock_put(sk);
}
/**
@@ -596,8 +601,11 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
spin_unlock(&can_rcvlists_lock);
/* schedule the receiver item for deletion */
- if (r)
+ if (r) {
+ if (r->sk)
+ sock_hold(r->sk);
call_rcu(&r->rcu, can_rx_delete_receiver);
+ }
}
EXPORT_SYMBOL(can_rx_unregister);
diff --git a/net/can/af_can.h b/net/can/af_can.h
index fca0fe9fc45a..b86f5129e838 100644
--- a/net/can/af_can.h
+++ b/net/can/af_can.h
@@ -50,13 +50,14 @@
struct receiver {
struct hlist_node list;
- struct rcu_head rcu;
canid_t can_id;
canid_t mask;
unsigned long matches;
void (*func)(struct sk_buff *, void *);
void *data;
char *ident;
+ struct sock *sk;
+ struct rcu_head rcu;
};
#define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS)
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 24d66c1cc0cd..4ccfd356baed 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1179,7 +1179,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
err = can_rx_register(dev, op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op,
- "bcm");
+ "bcm", sk);
op->rx_reg_dev = dev;
dev_put(dev);
@@ -1188,7 +1188,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
} else
err = can_rx_register(NULL, op->can_id,
REGMASK(op->can_id),
- bcm_rx_handler, op, "bcm");
+ bcm_rx_handler, op, "bcm", sk);
if (err) {
/* this bcm rx op is broken -> remove it */
list_del(&op->list);
diff --git a/net/can/gw.c b/net/can/gw.c
index 455168718c2e..77c8af4047ef 100644
--- a/net/can/gw.c
+++ b/net/can/gw.c
@@ -442,7 +442,7 @@ static inline int cgw_register_filter(struct cgw_job *gwj)
{
return can_rx_register(gwj->src.dev, gwj->ccgw.filter.can_id,
gwj->ccgw.filter.can_mask, can_can_gw_rcv,
- gwj, "gw");
+ gwj, "gw", NULL);
}
static inline void cgw_unregister_filter(struct cgw_job *gwj)
diff --git a/net/can/raw.c b/net/can/raw.c
index 56af689ca999..e9403a26a1d5 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -190,7 +190,7 @@ static int raw_enable_filters(struct net_device *dev, struct sock *sk,
for (i = 0; i < count; i++) {
err = can_rx_register(dev, filter[i].can_id,
filter[i].can_mask,
- raw_rcv, sk, "raw");
+ raw_rcv, sk, "raw", sk);
if (err) {
/* clean up successfully registered filters */
while (--i >= 0)
@@ -211,7 +211,7 @@ static int raw_enable_errfilter(struct net_device *dev, struct sock *sk,
if (err_mask)
err = can_rx_register(dev, 0, err_mask | CAN_ERR_FLAG,
- raw_rcv, sk, "raw");
+ raw_rcv, sk, "raw", sk);
return err;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index 1d24d5e54ac0..51aed87e8eec 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1678,24 +1678,19 @@ EXPORT_SYMBOL_GPL(net_dec_ingress_queue);
static struct static_key netstamp_needed __read_mostly;
#ifdef HAVE_JUMP_LABEL
-/* We are not allowed to call static_key_slow_dec() from irq context
- * If net_disable_timestamp() is called from irq context, defer the
- * static_key_slow_dec() calls.
- */
static atomic_t netstamp_needed_deferred;
-#endif
-
-void net_enable_timestamp(void)
+static void netstamp_clear(struct work_struct *work)
{
-#ifdef HAVE_JUMP_LABEL
int deferred = atomic_xchg(&netstamp_needed_deferred, 0);
- if (deferred) {
- while (--deferred)
- static_key_slow_dec(&netstamp_needed);
- return;
- }
+ while (deferred--)
+ static_key_slow_dec(&netstamp_needed);
+}
+static DECLARE_WORK(netstamp_work, netstamp_clear);
#endif
+
+void net_enable_timestamp(void)
+{
static_key_slow_inc(&netstamp_needed);
}
EXPORT_SYMBOL(net_enable_timestamp);
@@ -1703,12 +1698,12 @@ EXPORT_SYMBOL(net_enable_timestamp);
void net_disable_timestamp(void)
{
#ifdef HAVE_JUMP_LABEL
- if (in_interrupt()) {
- atomic_inc(&netstamp_needed_deferred);
- return;
- }
-#endif
+ /* net_disable_timestamp() can be called from non process context */
+ atomic_inc(&netstamp_needed_deferred);
+ schedule_work(&netstamp_work);
+#else
static_key_slow_dec(&netstamp_needed);
+#endif
}
EXPORT_SYMBOL(net_disable_timestamp);
diff --git a/net/dccp/input.c b/net/dccp/input.c
index 3bd14e885396..dbe2573f6ba1 100644
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -606,7 +606,8 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
skb) < 0)
return 1;
- goto discard;
+ consume_skb(skb);
+ return 0;
}
if (dh->dccph_type == DCCP_PKT_RESET)
goto discard;
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index de85d4e1cf43..52dcd414c2af 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -353,6 +353,7 @@ void ether_setup(struct net_device *dev)
dev->header_ops = &eth_header_ops;
dev->type = ARPHRD_ETHER;
dev->hard_header_len = ETH_HLEN;
+ dev->min_header_len = ETH_HLEN;
dev->mtu = ETH_DATA_LEN;
dev->addr_len = ETH_ALEN;
dev->tx_queue_len = 1000; /* Ethernet wants good queues */
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index bdb2a07ec363..6cc3e1d602fb 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -1657,6 +1657,10 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
goto validate_return_locked;
}
+ if (opt_iter + 1 == opt_len) {
+ err_offset = opt_iter;
+ goto validate_return_locked;
+ }
tag_len = tag[1];
if (tag_len > (opt_len - opt_iter)) {
err_offset = opt_iter + 1;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 9ce202549e7a..f300d1cbfa91 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -105,10 +105,10 @@ static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb,
if (skb->ip_summed != CHECKSUM_COMPLETE)
return;
- if (offset != 0)
- csum = csum_sub(csum,
- csum_partial(skb->data + tlen,
- offset, 0));
+ if (offset != 0) {
+ int tend_off = skb_transport_offset(skb) + tlen;
+ csum = csum_sub(csum, skb_checksum(skb, tend_off, offset, 0));
+ }
put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum);
}
@@ -1192,7 +1192,14 @@ void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb)
pktinfo->ipi_ifindex = 0;
pktinfo->ipi_spec_dst.s_addr = 0;
}
- skb_dst_drop(skb);
+ /* We need to keep the dst for __ip_options_echo()
+ * We could restrict the test to opt.ts_needtime || opt.srr,
+ * but the following is good enough as IP options are not often used.
+ */
+ if (unlikely(IPCB(skb)->opt.optlen))
+ skb_dst_force(skb);
+ else
+ skb_dst_drop(skb);
}
int ip_setsockopt(struct sock *sk, int level,
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index e29249bc23b8..3a2b21e22629 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -645,6 +645,8 @@ static int ping_v4_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh,
{
struct sk_buff *skb = skb_peek(&sk->sk_write_queue);
+ if (!skb)
+ return 0;
pfh->wcheck = csum_partial((char *)&pfh->icmph,
sizeof(struct icmphdr), pfh->wcheck);
pfh->icmph.checksum = csum_fold(pfh->wcheck);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 676566faf649..4ab7735e43ab 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -789,6 +789,12 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos,
ret = -EAGAIN;
break;
}
+ /* if __tcp_splice_read() got nothing while we have
+ * an skb in receive queue, we do not want to loop.
+ * This might happen with URG data.
+ */
+ if (!skb_queue_empty(&sk->sk_receive_queue))
+ break;
sk_wait_data(sk, &timeo, NULL);
if (signal_pending(current)) {
ret = sock_intr_errno(timeo);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index ca3731721d81..8a62ad0c850b 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -2383,9 +2383,11 @@ u32 __tcp_select_window(struct sock *sk)
int full_space = min_t(int, tp->window_clamp, allowed_space);
int window;
- if (mss > full_space)
+ if (unlikely(mss > full_space)) {
mss = full_space;
-
+ if (mss <= 0)
+ return 0;
+ }
if (free_space < (full_space >> 1)) {
icsk->icsk_ack.quick = 0;
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index eba61b42cd42..ab0efaca4a78 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -55,6 +55,7 @@
#include <net/ip6_fib.h>
#include <net/ip6_route.h>
#include <net/ip6_tunnel.h>
+#include <net/gre.h>
static bool log_ecn_error = true;
@@ -367,35 +368,37 @@ static void ip6gre_tunnel_uninit(struct net_device *dev)
static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
- u8 type, u8 code, int offset, __be32 info)
+ u8 type, u8 code, int offset, __be32 info)
{
- const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)skb->data;
- __be16 *p = (__be16 *)(skb->data + offset);
- int grehlen = offset + 4;
+ const struct gre_base_hdr *greh;
+ const struct ipv6hdr *ipv6h;
+ int grehlen = sizeof(*greh);
struct ip6_tnl *t;
+ int key_off = 0;
__be16 flags;
+ __be32 key;
- flags = p[0];
- if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
- if (flags&(GRE_VERSION|GRE_ROUTING))
- return;
- if (flags&GRE_KEY) {
- grehlen += 4;
- if (flags&GRE_CSUM)
- grehlen += 4;
- }
+ if (!pskb_may_pull(skb, offset + grehlen))
+ return;
+ greh = (const struct gre_base_hdr *)(skb->data + offset);
+ flags = greh->flags;
+ if (flags & (GRE_VERSION | GRE_ROUTING))
+ return;
+ if (flags & GRE_CSUM)
+ grehlen += 4;
+ if (flags & GRE_KEY) {
+ key_off = grehlen + offset;
+ grehlen += 4;
}
- /* If only 8 bytes returned, keyed message will be dropped here */
- if (!pskb_may_pull(skb, grehlen))
+ if (!pskb_may_pull(skb, offset + grehlen))
return;
ipv6h = (const struct ipv6hdr *)skb->data;
- p = (__be16 *)(skb->data + offset);
+ greh = (const struct gre_base_hdr *)(skb->data + offset);
+ key = key_off ? *(__be32 *)(skb->data + key_off) : 0;
t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr,
- flags & GRE_KEY ?
- *(((__be32 *)p) + (grehlen / 4) - 1) : 0,
- p[1]);
+ key, greh->protocol);
if (!t)
return;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index c9bd1ee1f145..8b11a49c7dd7 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -479,18 +479,19 @@ ip6_tnl_dev_uninit(struct net_device *dev)
__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
{
- const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw;
- __u8 nexthdr = ipv6h->nexthdr;
- __u16 off = sizeof(*ipv6h);
+ const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)raw;
+ unsigned int nhoff = raw - skb->data;
+ unsigned int off = nhoff + sizeof(*ipv6h);
+ u8 next, nexthdr = ipv6h->nexthdr;
while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
- __u16 optlen = 0;
struct ipv6_opt_hdr *hdr;
- if (raw + off + sizeof(*hdr) > skb->data &&
- !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
+ u16 optlen;
+
+ if (!pskb_may_pull(skb, off + sizeof(*hdr)))
break;
- hdr = (struct ipv6_opt_hdr *) (raw + off);
+ hdr = (struct ipv6_opt_hdr *)(skb->data + off);
if (nexthdr == NEXTHDR_FRAGMENT) {
struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
if (frag_hdr->frag_off)
@@ -501,20 +502,29 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
} else {
optlen = ipv6_optlen(hdr);
}
+ /* cache hdr->nexthdr, since pskb_may_pull() might
+ * invalidate hdr
+ */
+ next = hdr->nexthdr;
if (nexthdr == NEXTHDR_DEST) {
- __u16 i = off + 2;
+ u16 i = 2;
+
+ /* Remember : hdr is no longer valid at this point. */
+ if (!pskb_may_pull(skb, off + optlen))
+ break;
+
while (1) {
struct ipv6_tlv_tnl_enc_lim *tel;
/* No more room for encapsulation limit */
- if (i + sizeof (*tel) > off + optlen)
+ if (i + sizeof(*tel) > optlen)
break;
- tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
+ tel = (struct ipv6_tlv_tnl_enc_lim *)(skb->data + off + i);
/* return index of option if found and valid */
if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
tel->length == 1)
- return i;
+ return i + off - nhoff;
/* else jump to next option */
if (tel->type)
i += tel->length + 2;
@@ -522,7 +532,7 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
i++;
}
}
- nexthdr = hdr->nexthdr;
+ nexthdr = next;
off += optlen;
}
return 0;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 3da2b16356eb..184f0fe35dc6 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -1389,6 +1389,7 @@ static int ipip6_tunnel_init(struct net_device *dev)
tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst);
if (!tunnel->dst_cache) {
free_percpu(dev->tstats);
+ dev->tstats = NULL;
return -ENOMEM;
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index a6079e7a6c6b..108b39967694 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -976,6 +976,16 @@ drop:
return 0; /* don't send reset */
}
+static void tcp_v6_restore_cb(struct sk_buff *skb)
+{
+ /* We need to move header back to the beginning if xfrm6_policy_check()
+ * and tcp_v6_fill_cb() are going to be called again.
+ * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there.
+ */
+ memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
+ sizeof(struct inet6_skb_parm));
+}
+
static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
struct dst_entry *dst,
@@ -1165,8 +1175,10 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
sk_gfp_atomic(sk, GFP_ATOMIC));
consume_skb(ireq->pktopts);
ireq->pktopts = NULL;
- if (newnp->pktoptions)
+ if (newnp->pktoptions) {
+ tcp_v6_restore_cb(newnp->pktoptions);
skb_set_owner_r(newnp->pktoptions, newsk);
+ }
}
}
@@ -1181,16 +1193,6 @@ out:
return NULL;
}
-static void tcp_v6_restore_cb(struct sk_buff *skb)
-{
- /* We need to move header back to the beginning if xfrm6_policy_check()
- * and tcp_v6_fill_cb() are going to be called again.
- * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there.
- */
- memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6,
- sizeof(struct inet6_skb_parm));
-}
-
/* The socket must have it's spinlock held when we get
* here, unless it is a TCP_LISTEN socket.
*
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 156a13c7ada8..003dd1d040ca 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -958,6 +958,64 @@ discard:
return 0;
}
+static struct sock *__udp6_lib_demux_lookup(struct net *net,
+ __be16 loc_port, const struct in6_addr *loc_addr,
+ __be16 rmt_port, const struct in6_addr *rmt_addr,
+ int dif)
+{
+ struct sock *sk;
+
+ rcu_read_lock();
+ sk = __udp6_lib_lookup(net, rmt_addr, rmt_port, loc_addr, loc_port,
+ dif, &udp_table);
+ if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
+ sk = NULL;
+ rcu_read_unlock();
+
+ return sk;
+}
+
+static void udp_v6_early_demux(struct sk_buff *skb)
+{
+ struct net *net = dev_net(skb->dev);
+ const struct udphdr *uh;
+ struct sock *sk;
+ struct dst_entry *dst;
+ int dif = skb->dev->ifindex;
+
+ if (!pskb_may_pull(skb, skb_transport_offset(skb) +
+ sizeof(struct udphdr)))
+ return;
+
+ uh = udp_hdr(skb);
+
+ if (skb->pkt_type == PACKET_HOST)
+ sk = __udp6_lib_demux_lookup(net, uh->dest,
+ &ipv6_hdr(skb)->daddr,
+ uh->source, &ipv6_hdr(skb)->saddr,
+ dif);
+ else
+ return;
+
+ if (!sk)
+ return;
+
+ skb->sk = sk;
+ skb->destructor = sock_efree;
+ dst = READ_ONCE(sk->sk_rx_dst);
+
+ if (dst)
+ dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie);
+ if (dst) {
+ if (dst->flags & DST_NOCACHE) {
+ if (likely(atomic_inc_not_zero(&dst->__refcnt)))
+ skb_dst_set(skb, dst);
+ } else {
+ skb_dst_set_noref(skb, dst);
+ }
+ }
+}
+
static __inline__ int udpv6_rcv(struct sk_buff *skb)
{
return __udp6_lib_rcv(skb, &udp_table, IPPROTO_UDP);
@@ -1461,6 +1519,7 @@ int compat_udpv6_getsockopt(struct sock *sk, int level, int optname,
#endif
static const struct inet6_protocol udpv6_protocol = {
+ .early_demux = udp_v6_early_demux,
.handler = udpv6_rcv,
.err_handler = udpv6_err,
.flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
diff --git a/net/irda/irqueue.c b/net/irda/irqueue.c
index acbe61c7e683..160dc89335e2 100644
--- a/net/irda/irqueue.c
+++ b/net/irda/irqueue.c
@@ -383,9 +383,6 @@ EXPORT_SYMBOL(hashbin_new);
* for deallocating this structure if it's complex. If not the user can
* just supply kfree, which should take care of the job.
*/
-#ifdef CONFIG_LOCKDEP
-static int hashbin_lock_depth = 0;
-#endif
int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func)
{
irda_queue_t* queue;
@@ -396,22 +393,27 @@ int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func)
IRDA_ASSERT(hashbin->magic == HB_MAGIC, return -1;);
/* Synchronize */
- if ( hashbin->hb_type & HB_LOCK ) {
- spin_lock_irqsave_nested(&hashbin->hb_spinlock, flags,
- hashbin_lock_depth++);
- }
+ if (hashbin->hb_type & HB_LOCK)
+ spin_lock_irqsave(&hashbin->hb_spinlock, flags);
/*
* Free the entries in the hashbin, TODO: use hashbin_clear when
* it has been shown to work
*/
for (i = 0; i < HASHBIN_SIZE; i ++ ) {
- queue = dequeue_first((irda_queue_t**) &hashbin->hb_queue[i]);
- while (queue ) {
- if (free_func)
- (*free_func)(queue);
- queue = dequeue_first(
- (irda_queue_t**) &hashbin->hb_queue[i]);
+ while (1) {
+ queue = dequeue_first((irda_queue_t**) &hashbin->hb_queue[i]);
+
+ if (!queue)
+ break;
+
+ if (free_func) {
+ if (hashbin->hb_type & HB_LOCK)
+ spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
+ free_func(queue);
+ if (hashbin->hb_type & HB_LOCK)
+ spin_lock_irqsave(&hashbin->hb_spinlock, flags);
+ }
}
}
@@ -420,12 +422,8 @@ int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func)
hashbin->magic = ~HB_MAGIC;
/* Release lock */
- if ( hashbin->hb_type & HB_LOCK) {
+ if (hashbin->hb_type & HB_LOCK)
spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
-#ifdef CONFIG_LOCKDEP
- hashbin_lock_depth--;
-#endif
- }
/*
* Free the hashbin structure
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 5871537af387..763e8e241ce3 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -273,6 +273,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb,
int l2tp_nl_register_ops(enum l2tp_pwtype pw_type,
const struct l2tp_nl_cmd_ops *ops);
void l2tp_nl_unregister_ops(enum l2tp_pwtype pw_type);
+int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg);
/* Session reference counts. Incremented when code obtains a reference
* to a session.
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c
index d0e906d39642..445b7cd0826a 100644
--- a/net/l2tp/l2tp_ip.c
+++ b/net/l2tp/l2tp_ip.c
@@ -11,6 +11,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <asm/ioctls.h>
#include <linux/icmp.h>
#include <linux/module.h>
#include <linux/skbuff.h>
@@ -555,6 +556,30 @@ out:
return err ? err : copied;
}
+int l2tp_ioctl(struct sock *sk, int cmd, unsigned long arg)
+{
+ struct sk_buff *skb;
+ int amount;
+
+ switch (cmd) {
+ case SIOCOUTQ:
+ amount = sk_wmem_alloc_get(sk);
+ break;
+ case SIOCINQ:
+ spin_lock_bh(&sk->sk_receive_queue.lock);
+ skb = skb_peek(&sk->sk_receive_queue);
+ amount = skb ? skb->len : 0;
+ spin_unlock_bh(&sk->sk_receive_queue.lock);
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return put_user(amount, (int __user *)arg);
+}
+EXPORT_SYMBOL(l2tp_ioctl);
+
static struct proto l2tp_ip_prot = {
.name = "L2TP/IP",
.owner = THIS_MODULE,
@@ -563,7 +588,7 @@ static struct proto l2tp_ip_prot = {
.bind = l2tp_ip_bind,
.connect = l2tp_ip_connect,
.disconnect = l2tp_ip_disconnect,
- .ioctl = udp_ioctl,
+ .ioctl = l2tp_ioctl,
.destroy = l2tp_ip_destroy_sock,
.setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt,
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index 0289208b0346..c8f483cd2ca9 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -715,7 +715,7 @@ static struct proto l2tp_ip6_prot = {
.bind = l2tp_ip6_bind,
.connect = l2tp_ip6_connect,
.disconnect = l2tp_ip6_disconnect,
- .ioctl = udp_ioctl,
+ .ioctl = l2tp_ioctl,
.destroy = l2tp_ip6_destroy_sock,
.setsockopt = ipv6_setsockopt,
.getsockopt = ipv6_getsockopt,
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index 3e821daf9dd4..8bc5a1bd2d45 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -821,7 +821,10 @@ void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb)
* another trick required to cope with how the PROCOM state
* machine works. -acme
*/
+ skb_orphan(skb);
+ sock_hold(sk);
skb->sk = sk;
+ skb->destructor = sock_efree;
}
if (!sock_owned_by_user(sk))
llc_conn_rcv(sk, skb);
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index d0e1e804ebd7..5404d0d195cc 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -290,7 +290,10 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb,
ev->type = LLC_SAP_EV_TYPE_PDU;
ev->reason = 0;
+ skb_orphan(skb);
+ sock_hold(sk);
skb->sk = sk;
+ skb->destructor = sock_efree;
llc_sap_state_process(sap, skb);
}
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 00a43a70e1fc..0402fa45b343 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -168,6 +168,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
break;
}
+ flush_delayed_work(&sdata->dec_tailroom_needed_wk);
drv_remove_interface(local, sdata);
}
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index f223d1c80ccf..d805cd577a60 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1497,6 +1497,8 @@ static void __fanout_link(struct sock *sk, struct packet_sock *po)
f->arr[f->num_members] = sk;
smp_wmb();
f->num_members++;
+ if (f->num_members == 1)
+ dev_add_pack(&f->prot_hook);
spin_unlock(&f->lock);
}
@@ -1513,6 +1515,8 @@ static void __fanout_unlink(struct sock *sk, struct packet_sock *po)
BUG_ON(i >= f->num_members);
f->arr[i] = f->arr[f->num_members - 1];
f->num_members--;
+ if (f->num_members == 0)
+ __dev_remove_pack(&f->prot_hook);
spin_unlock(&f->lock);
}
@@ -1623,6 +1627,7 @@ static void fanout_release_data(struct packet_fanout *f)
static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
{
+ struct packet_rollover *rollover = NULL;
struct packet_sock *po = pkt_sk(sk);
struct packet_fanout *f, *match;
u8 type = type_flags & 0xff;
@@ -1645,23 +1650,28 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
return -EINVAL;
}
+ mutex_lock(&fanout_mutex);
+
+ err = -EINVAL;
if (!po->running)
- return -EINVAL;
+ goto out;
+ err = -EALREADY;
if (po->fanout)
- return -EALREADY;
+ goto out;
if (type == PACKET_FANOUT_ROLLOVER ||
(type_flags & PACKET_FANOUT_FLAG_ROLLOVER)) {
- po->rollover = kzalloc(sizeof(*po->rollover), GFP_KERNEL);
- if (!po->rollover)
- return -ENOMEM;
- atomic_long_set(&po->rollover->num, 0);
- atomic_long_set(&po->rollover->num_huge, 0);
- atomic_long_set(&po->rollover->num_failed, 0);
+ err = -ENOMEM;
+ rollover = kzalloc(sizeof(*rollover), GFP_KERNEL);
+ if (!rollover)
+ goto out;
+ atomic_long_set(&rollover->num, 0);
+ atomic_long_set(&rollover->num_huge, 0);
+ atomic_long_set(&rollover->num_failed, 0);
+ po->rollover = rollover;
}
- mutex_lock(&fanout_mutex);
match = NULL;
list_for_each_entry(f, &fanout_list, list) {
if (f->id == id &&
@@ -1691,7 +1701,6 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
match->prot_hook.func = packet_rcv_fanout;
match->prot_hook.af_packet_priv = match;
match->prot_hook.id_match = match_fanout_group;
- dev_add_pack(&match->prot_hook);
list_add(&match->list, &fanout_list);
}
err = -EINVAL;
@@ -1708,36 +1717,40 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
}
}
out:
- mutex_unlock(&fanout_mutex);
- if (err) {
- kfree(po->rollover);
+ if (err && rollover) {
+ kfree(rollover);
po->rollover = NULL;
}
+ mutex_unlock(&fanout_mutex);
return err;
}
-static void fanout_release(struct sock *sk)
+/* If pkt_sk(sk)->fanout->sk_ref is zero, this function removes
+ * pkt_sk(sk)->fanout from fanout_list and returns pkt_sk(sk)->fanout.
+ * It is the responsibility of the caller to call fanout_release_data() and
+ * free the returned packet_fanout (after synchronize_net())
+ */
+static struct packet_fanout *fanout_release(struct sock *sk)
{
struct packet_sock *po = pkt_sk(sk);
struct packet_fanout *f;
+ mutex_lock(&fanout_mutex);
f = po->fanout;
- if (!f)
- return;
+ if (f) {
+ po->fanout = NULL;
- mutex_lock(&fanout_mutex);
- po->fanout = NULL;
+ if (atomic_dec_and_test(&f->sk_ref))
+ list_del(&f->list);
+ else
+ f = NULL;
- if (atomic_dec_and_test(&f->sk_ref)) {
- list_del(&f->list);
- dev_remove_pack(&f->prot_hook);
- fanout_release_data(f);
- kfree(f);
+ if (po->rollover)
+ kfree_rcu(po->rollover, rcu);
}
mutex_unlock(&fanout_mutex);
- if (po->rollover)
- kfree_rcu(po->rollover, rcu);
+ return f;
}
static bool packet_extra_vlan_len_allowed(const struct net_device *dev,
@@ -2637,7 +2650,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
int vnet_hdr_len;
struct packet_sock *po = pkt_sk(sk);
unsigned short gso_type = 0;
- int hlen, tlen;
+ int hlen, tlen, linear;
int extra_len = 0;
ssize_t n;
@@ -2741,8 +2754,9 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
err = -ENOBUFS;
hlen = LL_RESERVED_SPACE(dev);
tlen = dev->needed_tailroom;
- skb = packet_alloc_skb(sk, hlen + tlen, hlen, len,
- __virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len),
+ linear = __virtio16_to_cpu(vio_le(), vnet_hdr.hdr_len);
+ linear = max(linear, min_t(int, len, dev->hard_header_len));
+ skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, linear,
msg->msg_flags & MSG_DONTWAIT, &err);
if (skb == NULL)
goto out_unlock;
@@ -2845,6 +2859,7 @@ static int packet_release(struct socket *sock)
{
struct sock *sk = sock->sk;
struct packet_sock *po;
+ struct packet_fanout *f;
struct net *net;
union tpacket_req_u req_u;
@@ -2884,9 +2899,14 @@ static int packet_release(struct socket *sock)
packet_set_ring(sk, &req_u, 1, 1);
}
- fanout_release(sk);
+ f = fanout_release(sk);
synchronize_net();
+
+ if (f) {
+ fanout_release_data(f);
+ kfree(f);
+ }
/*
* Now the socket is dead. No more input will appear.
*/
@@ -3860,7 +3880,6 @@ static int packet_notifier(struct notifier_block *this,
}
if (msg == NETDEV_UNREGISTER) {
packet_cached_dev_reset(po);
- fanout_release(sk);
po->ifindex = -1;
if (po->prot_hook.dev)
dev_put(po->prot_hook.dev);
diff --git a/net/rmnet_data/rmnet_data_config.c b/net/rmnet_data/rmnet_data_config.c
index fb4c60fc2203..fad084d03854 100644
--- a/net/rmnet_data/rmnet_data_config.c
+++ b/net/rmnet_data/rmnet_data_config.c
@@ -638,6 +638,13 @@ void rmnet_config_netlink_msg_handler(struct sk_buff *skb)
rmnet_header->vnd.vnd_name);
break;
+ case RMNET_NETLINK_NEW_VND_WITH_NAME:
+ resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
+ resp_rmnet->return_code = rmnet_create_vnd_name(
+ rmnet_header->vnd.id,
+ rmnet_header->vnd.vnd_name);
+ break;
+
case RMNET_NETLINK_FREE_VND:
resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE;
/* Please check rmnet_vnd_free_dev documentation regarding
@@ -1087,11 +1094,11 @@ int rmnet_create_vnd(int id)
struct net_device *dev;
ASSERT_RTNL();
LOGL("(%d);", id);
- return rmnet_vnd_create_dev(id, &dev, NULL);
+ return rmnet_vnd_create_dev(id, &dev, NULL, 0);
}
/**
- * rmnet_create_vnd() - Create virtual network device node
+ * rmnet_create_vnd_prefix() - Create virtual network device node
* @id: RmNet virtual device node id
* @prefix: String prefix for device name
*
@@ -1103,7 +1110,24 @@ int rmnet_create_vnd_prefix(int id, const char *prefix)
struct net_device *dev;
ASSERT_RTNL();
LOGL("(%d, \"%s\");", id, prefix);
- return rmnet_vnd_create_dev(id, &dev, prefix);
+ return rmnet_vnd_create_dev(id, &dev, prefix, 0);
+}
+
+/**
+ * rmnet_create_vnd_name() - Create virtual network device node
+ * @id: RmNet virtual device node id
+ * @prefix: String prefix for device name
+ *
+ * Return:
+ * - result of rmnet_vnd_create_dev()
+ */
+int rmnet_create_vnd_name(int id, const char *name)
+{
+ struct net_device *dev;
+
+ ASSERT_RTNL();
+ LOGL("(%d, \"%s\");", id, name);
+ return rmnet_vnd_create_dev(id, &dev, name, 1);
}
/**
diff --git a/net/rmnet_data/rmnet_data_config.h b/net/rmnet_data/rmnet_data_config.h
index f19fbb378111..208c3a40c3ae 100644
--- a/net/rmnet_data/rmnet_data_config.h
+++ b/net/rmnet_data/rmnet_data_config.h
@@ -124,6 +124,7 @@ int rmnet_config_notify_cb(struct notifier_block *nb,
unsigned long event, void *data);
int rmnet_create_vnd(int id);
int rmnet_create_vnd_prefix(int id, const char *name);
+int rmnet_create_vnd_name(int id, const char *name);
int rmnet_free_vnd(int id);
struct rmnet_phys_ep_config *_rmnet_get_phys_ep_config
diff --git a/net/rmnet_data/rmnet_data_vnd.c b/net/rmnet_data/rmnet_data_vnd.c
index 2819da9ae3f2..ede1a54661cd 100644
--- a/net/rmnet_data/rmnet_data_vnd.c
+++ b/net/rmnet_data/rmnet_data_vnd.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -565,7 +565,7 @@ int rmnet_vnd_init(void)
* - RMNET_CONFIG_UNKNOWN_ERROR if register_netdevice() fails
*/
int rmnet_vnd_create_dev(int id, struct net_device **new_device,
- const char *prefix)
+ const char *prefix, int use_name)
{
struct net_device *dev;
char dev_prefix[IFNAMSIZ];
@@ -581,12 +581,15 @@ int rmnet_vnd_create_dev(int id, struct net_device **new_device,
return RMNET_CONFIG_DEVICE_IN_USE;
}
- if (!prefix)
+ if (!prefix && !use_name)
p = scnprintf(dev_prefix, IFNAMSIZ, "%s%%d",
RMNET_DATA_DEV_NAME_STR);
+ else if (prefix && use_name)
+ p = scnprintf(dev_prefix, IFNAMSIZ, "%s", prefix);
+ else if (prefix && !use_name)
+ p = scnprintf(dev_prefix, IFNAMSIZ, "%s%%d", prefix);
else
- p = scnprintf(dev_prefix, IFNAMSIZ, "%s%%d",
- prefix);
+ return RMNET_CONFIG_BAD_ARGUMENTS;
if (p >= (IFNAMSIZ-1)) {
LOGE("Specified prefix longer than IFNAMSIZ");
return RMNET_CONFIG_BAD_ARGUMENTS;
@@ -594,7 +597,7 @@ int rmnet_vnd_create_dev(int id, struct net_device **new_device,
dev = alloc_netdev(sizeof(struct rmnet_vnd_private_s),
dev_prefix,
- NET_NAME_ENUM,
+ use_name ? NET_NAME_UNKNOWN : NET_NAME_ENUM,
rmnet_vnd_setup);
if (!dev) {
LOGE("Failed to to allocate netdev for id %d", id);
diff --git a/net/rmnet_data/rmnet_data_vnd.h b/net/rmnet_data/rmnet_data_vnd.h
index 22ffcfc2e08e..7a1af24fa051 100644
--- a/net/rmnet_data/rmnet_data_vnd.h
+++ b/net/rmnet_data/rmnet_data_vnd.h
@@ -1,5 +1,5 @@
/*
- * 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
@@ -27,7 +27,7 @@ int rmnet_vnd_do_flow_control(struct net_device *dev,
struct rmnet_logical_ep_conf_s *rmnet_vnd_get_le_config(struct net_device *dev);
int rmnet_vnd_get_name(int id, char *name, int name_len);
int rmnet_vnd_create_dev(int id, struct net_device **new_device,
- const char *prefix);
+ const char *prefix, int use_name);
int rmnet_vnd_free_dev(int id);
int rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev);
int rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index b5fd4ab56156..138f2d667212 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -6960,7 +6960,8 @@ static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
*/
release_sock(sk);
current_timeo = schedule_timeout(current_timeo);
- BUG_ON(sk != asoc->base.sk);
+ if (sk != asoc->base.sk)
+ goto do_error;
lock_sock(sk);
*timeo_p = current_timeo;
diff --git a/net/socket.c b/net/socket.c
index bb11725c0e50..11a2967eaebc 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2245,8 +2245,10 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
return err;
err = sock_error(sock->sk);
- if (err)
+ if (err) {
+ datagrams = err;
goto out_put;
+ }
entry = mmsg;
compat_entry = (struct compat_mmsghdr __user *)mmsg;
diff --git a/net/wireless/db.txt b/net/wireless/db.txt
index 7013eb1313a2..449e4a31a3ec 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -268,7 +268,7 @@ country CN: DFS-FCC
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (23), AUTO-BW
(5250 - 5330 @ 80), (23), DFS, AUTO-BW
- (5735 - 5835 @ 80), (30)
+ (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)
diff --git a/Documentation/mic/mpssd/.gitignore b/samples/mic/mpssd/.gitignore
index 8b7c72f07c92..8b7c72f07c92 100644
--- a/Documentation/mic/mpssd/.gitignore
+++ b/samples/mic/mpssd/.gitignore
diff --git a/samples/mic/mpssd/Makefile b/samples/mic/mpssd/Makefile
new file mode 100644
index 000000000000..3e3ef91fed6b
--- /dev/null
+++ b/samples/mic/mpssd/Makefile
@@ -0,0 +1,27 @@
+ifndef CROSS_COMPILE
+uname_M := $(shell uname -m 2>/dev/null || echo not)
+ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
+
+ifeq ($(ARCH),x86)
+
+PROGS := mpssd
+CC = $(CROSS_COMPILE)gcc
+CFLAGS := -I../../../usr/include -I../../../tools/include
+
+ifdef DEBUG
+CFLAGS += -DDEBUG=$(DEBUG)
+endif
+
+all: $(PROGS)
+mpssd: mpssd.c sysfs.c
+ $(CC) $(CFLAGS) mpssd.c sysfs.c -o mpssd -lpthread
+
+install:
+ install mpssd /usr/sbin/mpssd
+ install micctrl /usr/sbin/micctrl
+
+clean:
+ rm -fr $(PROGS)
+
+endif
+endif
diff --git a/Documentation/mic/mpssd/micctrl b/samples/mic/mpssd/micctrl
index 8f2629b41c5f..8f2629b41c5f 100755..100644
--- a/Documentation/mic/mpssd/micctrl
+++ b/samples/mic/mpssd/micctrl
diff --git a/Documentation/mic/mpssd/mpss b/samples/mic/mpssd/mpss
index 09ea90931649..09ea90931649 100755..100644
--- a/Documentation/mic/mpssd/mpss
+++ b/samples/mic/mpssd/mpss
diff --git a/Documentation/mic/mpssd/mpssd.c b/samples/mic/mpssd/mpssd.c
index c99a75968c01..c99a75968c01 100644
--- a/Documentation/mic/mpssd/mpssd.c
+++ b/samples/mic/mpssd/mpssd.c
diff --git a/Documentation/mic/mpssd/mpssd.h b/samples/mic/mpssd/mpssd.h
index 8bd64944aacc..8bd64944aacc 100644
--- a/Documentation/mic/mpssd/mpssd.h
+++ b/samples/mic/mpssd/mpssd.h
diff --git a/Documentation/mic/mpssd/sysfs.c b/samples/mic/mpssd/sysfs.c
index 8dd326936083..8dd326936083 100644
--- a/Documentation/mic/mpssd/sysfs.c
+++ b/samples/mic/mpssd/sysfs.c
diff --git a/samples/seccomp/bpf-helper.h b/samples/seccomp/bpf-helper.h
index 38ee70f3cd5b..1d8de9edd858 100644
--- a/samples/seccomp/bpf-helper.h
+++ b/samples/seccomp/bpf-helper.h
@@ -138,7 +138,7 @@ union arg64 {
#define ARG_32(idx) \
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx))
-/* Loads hi into A and lo in X */
+/* Loads lo into M[0] and hi into M[1] and A */
#define ARG_64(idx) \
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, LO_ARG(idx)), \
BPF_STMT(BPF_ST, 0), /* lo -> M[0] */ \
@@ -153,88 +153,107 @@ union arg64 {
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (value), 1, 0), \
jt
-/* Checks the lo, then swaps to check the hi. A=lo,X=hi */
+#define JA32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \
+ jt
+
+#define JGE32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \
+ jt
+
+#define JGT32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \
+ jt
+
+#define JLE32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \
+ jt
+
+#define JLT32(value, jt) \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \
+ jt
+
+/*
+ * All the JXX64 checks assume lo is saved in M[0] and hi is saved in both
+ * A and M[1]. This invariant is kept by restoring A if necessary.
+ */
#define JEQ64(lo, hi, jt) \
+ /* if (hi != arg.hi) goto NOMATCH; */ \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ /* if (lo != arg.lo) goto NOMATCH; */ \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 0, 2), \
- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
jt, \
- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
#define JNE64(lo, hi, jt) \
- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 5, 0), \
- BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ /* if (hi != arg.hi) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), \
+ /* if (lo != arg.lo) goto MATCH; */ \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (lo), 2, 0), \
- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
jt, \
- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
-
-#define JA32(value, jt) \
- BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (value), 0, 1), \
- jt
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
#define JA64(lo, hi, jt) \
+ /* if (hi & arg.hi) goto MATCH; */ \
BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (hi), 3, 0), \
- BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), \
+ /* if (lo & arg.lo) goto MATCH; */ \
BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, (lo), 0, 2), \
- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
jt, \
- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
-#define JGE32(value, jt) \
- BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 0, 1), \
- jt
-
-#define JLT32(value, jt) \
- BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (value), 1, 0), \
- jt
-
-/* Shortcut checking if hi > arg.hi. */
#define JGE64(lo, hi, jt) \
+ /* if (hi > arg.hi) goto MATCH; */ \
BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \
+ /* if (hi != arg.hi) goto NOMATCH; */ \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
- BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), \
+ /* if (lo >= arg.lo) goto MATCH; */ \
BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 0, 2), \
- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
- jt, \
- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
-
-#define JLT64(lo, hi, jt) \
- BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
- BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
- BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \
- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
jt, \
- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
-#define JGT32(value, jt) \
- BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 0, 1), \
- jt
-
-#define JLE32(value, jt) \
- BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (value), 1, 0), \
- jt
-
-/* Check hi > args.hi first, then do the GE checking */
#define JGT64(lo, hi, jt) \
+ /* if (hi > arg.hi) goto MATCH; */ \
BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 4, 0), \
+ /* if (hi != arg.hi) goto NOMATCH; */ \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
- BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), \
+ /* if (lo > arg.lo) goto MATCH; */ \
BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 0, 2), \
- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
jt, \
- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
#define JLE64(lo, hi, jt) \
- BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (hi), 6, 0), \
- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 3), \
- BPF_STMT(BPF_LD+BPF_MEM, 0), /* swap in lo */ \
+ /* if (hi < arg.hi) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
+ /* if (hi != arg.hi) goto NOMATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), \
+ /* if (lo <= arg.lo) goto MATCH; */ \
BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, (lo), 2, 0), \
- BPF_STMT(BPF_LD+BPF_MEM, 1), /* passed: swap hi back in */ \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
+ jt, \
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
+
+#define JLT64(lo, hi, jt) \
+ /* if (hi < arg.hi) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (hi), 0, 4), \
+ /* if (hi != arg.hi) goto NOMATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (hi), 0, 5), \
+ BPF_STMT(BPF_LD+BPF_MEM, 0), \
+ /* if (lo < arg.lo) goto MATCH; */ \
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, (lo), 2, 0), \
+ BPF_STMT(BPF_LD+BPF_MEM, 1), \
jt, \
- BPF_STMT(BPF_LD+BPF_MEM, 1) /* failed: swap hi back in */
+ BPF_STMT(BPF_LD+BPF_MEM, 1)
#define LOAD_SYSCALL_NR \
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
index 1d5acbe0c08b..86240d02b530 100644
--- a/sound/core/seq/seq_fifo.c
+++ b/sound/core/seq/seq_fifo.c
@@ -135,6 +135,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
f->tail = cell;
if (f->head == NULL)
f->head = cell;
+ cell->next = NULL;
f->cells++;
spin_unlock_irqrestore(&f->lock, flags);
@@ -214,6 +215,8 @@ void snd_seq_fifo_cell_putback(struct snd_seq_fifo *f,
spin_lock_irqsave(&f->lock, flags);
cell->next = f->head;
f->head = cell;
+ if (!f->tail)
+ f->tail = cell;
f->cells++;
spin_unlock_irqrestore(&f->lock, flags);
}
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 05a31df05c00..30b28e80c6e6 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1704,9 +1704,21 @@ static int snd_timer_user_params(struct file *file,
return -EBADFD;
if (copy_from_user(&params, _params, sizeof(params)))
return -EFAULT;
- if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) {
- err = -EINVAL;
- goto _end;
+ if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) {
+ u64 resolution;
+
+ if (params.ticks < 1) {
+ err = -EINVAL;
+ goto _end;
+ }
+
+ /* Don't allow resolution less than 1ms */
+ resolution = snd_timer_resolution(tu->timeri);
+ resolution *= params.ticks;
+ if (resolution < 1000000) {
+ err = -EINVAL;
+ goto _end;
+ }
}
if (params.queue_size > 0 &&
(params.queue_size < 32 || params.queue_size > 1024)) {
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index 9667cbfb0ca2..ab4cdab5cfa5 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -27,12 +27,6 @@
#include "cthw20k1.h"
#include "ct20k1reg.h"
-#if BITS_PER_LONG == 32
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */
-#else
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */
-#endif
-
struct hw20k1 {
struct hw hw;
spinlock_t reg_20k1_lock;
@@ -1904,19 +1898,18 @@ static int hw_card_start(struct hw *hw)
{
int err;
struct pci_dev *pci = hw->pci;
+ const unsigned int dma_bits = BITS_PER_LONG;
err = pci_enable_device(pci);
if (err < 0)
return err;
/* Set DMA transfer mask */
- if (dma_set_mask(&pci->dev, CT_XFI_DMA_MASK) < 0 ||
- dma_set_coherent_mask(&pci->dev, CT_XFI_DMA_MASK) < 0) {
- dev_err(hw->card->dev,
- "architecture does not support PCI busmaster DMA with mask 0x%llx\n",
- CT_XFI_DMA_MASK);
- err = -ENXIO;
- goto error1;
+ if (dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
+ } else {
+ dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
}
if (!hw->io_base) {
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c
index 9dc2950e1ab7..d86678c2a957 100644
--- a/sound/pci/ctxfi/cthw20k2.c
+++ b/sound/pci/ctxfi/cthw20k2.c
@@ -26,12 +26,6 @@
#include "cthw20k2.h"
#include "ct20k2reg.h"
-#if BITS_PER_LONG == 32
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */
-#else
-#define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */
-#endif
-
struct hw20k2 {
struct hw hw;
/* for i2c */
@@ -2029,19 +2023,18 @@ static int hw_card_start(struct hw *hw)
int err = 0;
struct pci_dev *pci = hw->pci;
unsigned int gctl;
+ const unsigned int dma_bits = BITS_PER_LONG;
err = pci_enable_device(pci);
if (err < 0)
return err;
/* Set DMA transfer mask */
- if (dma_set_mask(&pci->dev, CT_XFI_DMA_MASK) < 0 ||
- dma_set_coherent_mask(&pci->dev, CT_XFI_DMA_MASK) < 0) {
- dev_err(hw->card->dev,
- "architecture does not support PCI busmaster DMA with mask 0x%llx\n",
- CT_XFI_DMA_MASK);
- err = -ENXIO;
- goto error1;
+ if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(dma_bits))) {
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(dma_bits));
+ } else {
+ dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
+ dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
}
if (!hw->io_base) {
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index ad4a1e9a3ae1..8f3e5e9d8bdb 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -2208,9 +2208,9 @@ static const struct pci_device_id azx_ids[] = {
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Lewisburg */
{ PCI_DEVICE(0x8086, 0xa1f0),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
{ PCI_DEVICE(0x8086, 0xa270),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
/* Lynx Point-LP */
{ PCI_DEVICE(0x8086, 0x9c20),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 00c50d58f108..cf0785ddbd14 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -5560,6 +5560,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME),
+ SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -5674,6 +5675,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460),
SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
+ SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
@@ -6047,6 +6049,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC298_STANDARD_PINS,
{0x17, 0x90170150}),
+ SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_SPK_VOLUME,
+ {0x12, 0xb7a60140},
+ {0x13, 0xb7a60150},
+ {0x17, 0x90170110},
+ {0x1a, 0x03011020},
+ {0x21, 0x03211030}),
{}
};
diff --git a/sound/soc/codecs/audio-ext-clk-up.c b/sound/soc/codecs/audio-ext-clk-up.c
index 6de88aff0dd4..cb230f38db22 100644
--- a/sound/soc/codecs/audio-ext-clk-up.c
+++ b/sound/soc/codecs/audio-ext-clk-up.c
@@ -34,6 +34,7 @@ struct pinctrl_info {
struct pinctrl *pinctrl;
struct pinctrl_state *sleep;
struct pinctrl_state *active;
+ char __iomem *base;
};
struct audio_ext_ap_clk {
@@ -192,8 +193,10 @@ static int audio_ext_lpass_mclk_prepare(struct clk_hw *hw)
pr_err("%s afe_set_digital_codec_core_clock failed\n",
__func__);
return ret;
- }
+ }
+ if (pnctrl_info->base)
+ iowrite32(1, pnctrl_info->base);
return 0;
}
@@ -219,6 +222,8 @@ static void audio_ext_lpass_mclk_unprepare(struct clk_hw *hw)
if (ret < 0)
pr_err("%s: afe_set_digital_codec_core_clock failed, ret = %d\n",
__func__, ret);
+ if (pnctrl_info->base)
+ iowrite32(0, pnctrl_info->base);
}
static int audio_ext_lpass_mclk2_prepare(struct clk_hw *hw)
@@ -381,9 +386,11 @@ static struct clk_hw *audio_msm_hws1[] = {
static int audio_get_pinctrl(struct platform_device *pdev,
enum audio_clk_mux mux)
{
+ struct device *dev = &pdev->dev;
struct pinctrl_info *pnctrl_info;
struct pinctrl *pinctrl;
int ret;
+ u32 reg;
switch (mux) {
case AP_CLK2:
@@ -396,21 +403,20 @@ static int audio_get_pinctrl(struct platform_device *pdev,
pnctrl_info = &audio_lpass_mclk2.pnctrl_info;
break;
default:
- dev_err(&pdev->dev, "%s Not a valid MUX ID: %d\n",
+ dev_err(dev, "%s Not a valid MUX ID: %d\n",
__func__, mux);
return -EINVAL;
}
- pnctrl_info = &audio_ap_clk2.pnctrl_info;
if (pnctrl_info->pinctrl) {
- dev_dbg(&pdev->dev, "%s: already requested before\n",
+ dev_dbg(dev, "%s: already requested before\n",
__func__);
return -EINVAL;
}
- pinctrl = devm_pinctrl_get(&pdev->dev);
+ pinctrl = devm_pinctrl_get(dev);
if (IS_ERR_OR_NULL(pinctrl)) {
- dev_dbg(&pdev->dev, "%s: Unable to get pinctrl handle\n",
+ dev_dbg(dev, "%s: Unable to get pinctrl handle\n",
__func__);
return -EINVAL;
}
@@ -418,13 +424,13 @@ static int audio_get_pinctrl(struct platform_device *pdev,
/* get all state handles from Device Tree */
pnctrl_info->sleep = pinctrl_lookup_state(pinctrl, "sleep");
if (IS_ERR(pnctrl_info->sleep)) {
- dev_err(&pdev->dev, "%s: could not get sleep pinstate\n",
+ dev_err(dev, "%s: could not get sleep pinstate\n",
__func__);
goto err;
}
pnctrl_info->active = pinctrl_lookup_state(pinctrl, "active");
if (IS_ERR(pnctrl_info->active)) {
- dev_err(&pdev->dev, "%s: could not get active pinstate\n",
+ dev_err(dev, "%s: could not get active pinstate\n",
__func__);
goto err;
}
@@ -432,10 +438,22 @@ static int audio_get_pinctrl(struct platform_device *pdev,
ret = pinctrl_select_state(pnctrl_info->pinctrl,
pnctrl_info->sleep);
if (ret) {
- dev_err(&pdev->dev, "%s: Disable TLMM pins failed with %d\n",
+ dev_err(dev, "%s: Disable TLMM pins failed with %d\n",
__func__, ret);
goto err;
}
+
+ ret = of_property_read_u32(dev->of_node, "qcom,mclk-clk-reg", &reg);
+ if (ret < 0) {
+ dev_dbg(dev, "miss mclk reg\n");
+ } else {
+ pnctrl_info->base = ioremap(reg, sizeof(u32));
+ if (pnctrl_info->base == NULL) {
+ dev_err(dev, "%s ioremap failed\n", __func__);
+ goto err;
+ }
+ }
+
return 0;
err:
diff --git a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
index 1d1dd0f61f28..db723e5ec1f4 100644
--- a/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
@@ -854,8 +854,8 @@ static int msm_sdw_config_compander(struct snd_soc_codec *codec, int comp,
if (!msm_sdw->comp_enabled[comp])
return 0;
- comp_ctl0_reg = MSM_SDW_COMPANDER7_CTL0 + (comp * 8);
- rx_path_cfg0_reg = MSM_SDW_RX7_RX_PATH_CFG0 + (comp * 20);
+ comp_ctl0_reg = MSM_SDW_COMPANDER7_CTL0 + (comp * 0x20);
+ rx_path_cfg0_reg = MSM_SDW_RX7_RX_PATH_CFG0 + (comp * 0x1E0);
if (SND_SOC_DAPM_EVENT_ON(event)) {
/* Enable Compander Clock */
@@ -1044,7 +1044,7 @@ static int msm_sdw_swrm_read(void *handle, int reg)
* Add sleep as SWR slave access read takes time.
* Allow for RD_DONE to complete for previous register if any.
*/
- usleep_range(50, 55);
+ usleep_range(100, 105);
/* read_lock */
mutex_lock(&msm_sdw->sdw_read_lock);
@@ -1079,6 +1079,11 @@ static int msm_sdw_bulk_write(struct msm_sdw_priv *msm_sdw,
sdw_wr_addr_base = MSM_SDW_AHB_BRIDGE_WR_ADDR_0;
sdw_wr_data_base = MSM_SDW_AHB_BRIDGE_WR_DATA_0;
+ /*
+ * Add sleep as SWR slave write takes time.
+ * Allow for any previous pending write to complete.
+ */
+ usleep_range(50, 55);
for (i = 0; i < len; i += 2) {
/* First Write the Data to register */
ret = regmap_bulk_write(msm_sdw->regmap,
@@ -1656,12 +1661,15 @@ static int msm_sdw_notifier_service_cb(struct notifier_block *nb,
service_nb);
bool adsp_ready = false;
unsigned long timeout;
+ static bool initial_boot = true;
pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode);
mutex_lock(&msm_sdw->codec_mutex);
switch (opcode) {
case AUDIO_NOTIFIER_SERVICE_DOWN:
+ if (initial_boot)
+ break;
msm_sdw->int_mclk1_enabled = false;
msm_sdw->dev_up = false;
for (i = 0; i < msm_sdw->nr; i++)
@@ -1669,6 +1677,8 @@ static int msm_sdw_notifier_service_cb(struct notifier_block *nb,
SWR_DEVICE_DOWN, NULL);
break;
case AUDIO_NOTIFIER_SERVICE_UP:
+ if (initial_boot)
+ initial_boot = false;
if (!q6core_is_adsp_ready()) {
dev_dbg(msm_sdw->dev, "ADSP isn't ready\n");
timeout = jiffies +
diff --git a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
index 04440262fe7a..699e7251023f 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -1436,11 +1436,11 @@ static int msm_anlg_cdc_codec_enable_clock_block(struct snd_soc_codec *codec,
if (enable) {
snd_soc_update_bits(codec,
MSM89XX_PMIC_ANALOG_MASTER_BIAS_CTL, 0x30, 0x30);
+ msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_CLK_ON);
snd_soc_update_bits(codec,
MSM89XX_PMIC_DIGITAL_CDC_RST_CTL, 0x80, 0x80);
snd_soc_update_bits(codec,
MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x0C);
- msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_CLK_ON);
} else {
snd_soc_update_bits(codec,
MSM89XX_PMIC_DIGITAL_CDC_TOP_CLK_CTL, 0x0C, 0x00);
@@ -3181,7 +3181,7 @@ static struct snd_soc_dai_driver msm_anlg_cdc_i2s_dai[] = {
.name = "msm_anlg_cdc_i2s_rx1",
.id = AIF1_PB,
.playback = {
- .stream_name = "Playback",
+ .stream_name = "PDM Playback",
.rates = SDM660_CDC_RATES,
.formats = SDM660_CDC_FORMATS,
.rate_max = 192000,
@@ -3195,7 +3195,7 @@ static struct snd_soc_dai_driver msm_anlg_cdc_i2s_dai[] = {
.name = "msm_anlg_cdc_i2s_tx1",
.id = AIF1_CAP,
.capture = {
- .stream_name = "Record",
+ .stream_name = "PDM Capture",
.rates = SDM660_CDC_RATES,
.formats = SDM660_CDC_FORMATS,
.rate_max = 48000,
@@ -3760,8 +3760,8 @@ static int msm_anlg_cdc_device_down(struct snd_soc_codec *codec)
snd_soc_write(codec,
MSM89XX_PMIC_ANALOG_SPKR_DAC_CTL, 0x93);
- atomic_set(&pdata->int_mclk0_enabled, false);
msm_anlg_cdc_dig_notifier_call(codec, DIG_CDC_EVENT_SSR_DOWN);
+ atomic_set(&pdata->int_mclk0_enabled, false);
set_bit(BUS_DOWN, &sdm660_cdc_priv->status_mask);
snd_soc_card_change_online_state(codec->component.card, 0);
@@ -3797,6 +3797,9 @@ static int msm_anlg_cdc_device_up(struct snd_soc_codec *codec)
msm_anlg_cdc_configure_cap(codec, false, false);
wcd_mbhc_stop(&sdm660_cdc_priv->mbhc);
wcd_mbhc_deinit(&sdm660_cdc_priv->mbhc);
+ /* Disable mechanical detection and set type to insertion */
+ snd_soc_update_bits(codec, MSM89XX_PMIC_ANALOG_MBHC_DET_CTL_1,
+ 0xA0, 0x20);
ret = wcd_mbhc_init(&sdm660_cdc_priv->mbhc, codec, &mbhc_cb,
&intr_ids, wcd_mbhc_registers, true);
if (ret)
@@ -3819,17 +3822,22 @@ static int sdm660_cdc_notifier_service_cb(struct notifier_block *nb,
bool adsp_ready = false;
bool timedout;
unsigned long timeout;
+ static bool initial_boot = true;
codec = sdm660_cdc_priv->codec;
dev_dbg(codec->dev, "%s: Service opcode 0x%lx\n", __func__, opcode);
switch (opcode) {
case AUDIO_NOTIFIER_SERVICE_DOWN:
+ if (initial_boot)
+ break;
dev_dbg(codec->dev,
"ADSP is about to power down. teardown/reset codec\n");
msm_anlg_cdc_device_down(codec);
break;
case AUDIO_NOTIFIER_SERVICE_UP:
+ if (initial_boot)
+ initial_boot = false;
dev_dbg(codec->dev,
"ADSP is about to power up. bring up codec\n");
@@ -4159,6 +4167,8 @@ static int msm_anlg_cdc_soc_probe(struct snd_soc_codec *codec)
snd_soc_dapm_ignore_suspend(dapm, "PDM Playback");
snd_soc_dapm_ignore_suspend(dapm, "PDM Capture");
+ snd_soc_dapm_sync(dapm);
+
return 0;
}
diff --git a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
index 1b56ef4d5fbe..c6074570bb50 100644
--- a/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
+++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
@@ -1028,7 +1028,7 @@ static int msm_dig_cdc_event_notify(struct notifier_block *block,
break;
case DIG_CDC_EVENT_PRE_RX1_INT_ON:
snd_soc_update_bits(codec,
- MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x14);
+ MSM89XX_CDC_CORE_RX1_B3_CTL, 0x3C, 0x28);
snd_soc_update_bits(codec,
MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0x10);
snd_soc_update_bits(codec,
@@ -1036,7 +1036,7 @@ static int msm_dig_cdc_event_notify(struct notifier_block *block,
break;
case DIG_CDC_EVENT_PRE_RX2_INT_ON:
snd_soc_update_bits(codec,
- MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x14);
+ MSM89XX_CDC_CORE_RX2_B3_CTL, 0x3C, 0x28);
snd_soc_update_bits(codec,
MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0x10);
snd_soc_update_bits(codec,
@@ -1044,7 +1044,7 @@ static int msm_dig_cdc_event_notify(struct notifier_block *block,
break;
case DIG_CDC_EVENT_POST_RX1_INT_OFF:
snd_soc_update_bits(codec,
- MSM89XX_CDC_CORE_RX1_B3_CTL, 0x1C, 0x00);
+ MSM89XX_CDC_CORE_RX1_B3_CTL, 0x3C, 0x00);
snd_soc_update_bits(codec,
MSM89XX_CDC_CORE_RX1_B4_CTL, 0x18, 0xFF);
snd_soc_update_bits(codec,
@@ -1052,7 +1052,7 @@ static int msm_dig_cdc_event_notify(struct notifier_block *block,
break;
case DIG_CDC_EVENT_POST_RX2_INT_OFF:
snd_soc_update_bits(codec,
- MSM89XX_CDC_CORE_RX2_B3_CTL, 0x1C, 0x00);
+ MSM89XX_CDC_CORE_RX2_B3_CTL, 0x3C, 0x00);
snd_soc_update_bits(codec,
MSM89XX_CDC_CORE_RX2_B4_CTL, 0x18, 0xFF);
snd_soc_update_bits(codec,
@@ -1207,6 +1207,8 @@ static int msm_dig_cdc_soc_probe(struct snd_soc_codec *codec)
snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX2");
snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX3");
+ snd_soc_dapm_sync(dapm);
+
return 0;
}
@@ -2016,7 +2018,7 @@ static struct snd_soc_codec_driver soc_msm_dig_codec = {
const struct regmap_config msm_digital_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
- .val_bits = 32,
+ .val_bits = 8,
.lock = enable_digital_callback,
.unlock = disable_digital_callback,
.cache_type = REGCACHE_FLAT,
@@ -2127,8 +2129,8 @@ static int msm_dig_resume(struct device *dev)
}
static const struct dev_pm_ops msm_dig_pm_ops = {
- .suspend = msm_dig_suspend,
- .resume = msm_dig_resume,
+ .suspend_late = msm_dig_suspend,
+ .resume_early = msm_dig_resume,
};
#endif
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index e6e40d1d6a8f..7f9ad8ebcd3d 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -53,7 +53,7 @@
#define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS 50
#define ANC_DETECT_RETRY_CNT 7
-#define WCD_MBHC_SPL_HS_CNT 2
+#define WCD_MBHC_SPL_HS_CNT 1
static int det_extn_cable_en;
module_param(det_extn_cable_en, int,
@@ -1162,7 +1162,7 @@ static void wcd_correct_swch_plug(struct work_struct *work)
bool wrk_complete = false;
int pt_gnd_mic_swap_cnt = 0;
int no_gnd_mic_swap_cnt = 0;
- bool is_pa_on = false, spl_hs = false;
+ bool is_pa_on = false, spl_hs = false, spl_hs_reported = false;
bool micbias2 = false;
bool micbias1 = false;
int ret = 0;
@@ -1368,6 +1368,16 @@ correct_plug_type:
plug_type);
if (!(plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) {
plug_type = MBHC_PLUG_TYPE_HEADSET;
+ if (!spl_hs_reported &&
+ spl_hs_count == WCD_MBHC_SPL_HS_CNT) {
+ spl_hs_reported = true;
+ WCD_MBHC_RSC_LOCK(mbhc);
+ wcd_mbhc_find_plug_and_report(mbhc,
+ plug_type);
+ WCD_MBHC_RSC_UNLOCK(mbhc);
+ continue;
+ } else if (spl_hs_reported)
+ continue;
/*
* Report headset only if not already reported
* and if there is not button press without
@@ -1442,6 +1452,29 @@ exit:
!mbhc->micbias_enable)
mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
MICB_DISABLE);
+
+ /*
+ * If plug type is corrected from special headset to headphone,
+ * clear the micbias enable flag, set micbias back to 1.8V and
+ * disable micbias.
+ */
+ if (plug_type == MBHC_PLUG_TYPE_HEADPHONE &&
+ mbhc->micbias_enable) {
+ if (mbhc->mbhc_cb->mbhc_micbias_control)
+ mbhc->mbhc_cb->mbhc_micbias_control(
+ codec, MIC_BIAS_2,
+ MICB_DISABLE);
+ if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
+ mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
+ codec,
+ MIC_BIAS_2, false);
+ if (mbhc->mbhc_cb->set_micbias_value) {
+ mbhc->mbhc_cb->set_micbias_value(codec);
+ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
+ }
+ mbhc->micbias_enable = false;
+ }
+
if (mbhc->mbhc_cb->micbias_enable_status) {
micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
MIC_BIAS_1);
@@ -2953,6 +2986,7 @@ void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->hph_right_ocp, mbhc);
if (mbhc->mbhc_cb && mbhc->mbhc_cb->register_notifier)
mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock, false);
+ wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
mutex_destroy(&mbhc->codec_resource_lock);
mutex_destroy(&mbhc->hphl_pa_lock);
mutex_destroy(&mbhc->hphr_pa_lock);
diff --git a/sound/soc/codecs/wcd-spi.c b/sound/soc/codecs/wcd-spi.c
index b03a8a9caed7..3d2fe2c6bed9 100644
--- a/sound/soc/codecs/wcd-spi.c
+++ b/sound/soc/codecs/wcd-spi.c
@@ -81,8 +81,15 @@
#define WCD_SPI_WORD_BYTE_CNT (4)
#define WCD_SPI_RW_MULTI_MIN_LEN (16)
-/* Max size is closest multiple of 16 less than 64Kbytes */
-#define WCD_SPI_RW_MULTI_MAX_LEN ((64 * 1024) - 16)
+/* Max size is 32 bytes less than 64Kbytes */
+#define WCD_SPI_RW_MULTI_MAX_LEN ((64 * 1024) - 32)
+
+/*
+ * Max size for the pre-allocated buffers is the max
+ * possible read/write length + 32 bytes for the SPI
+ * read/write command header itself.
+ */
+#define WCD_SPI_RW_MAX_BUF_SIZE (WCD_SPI_RW_MULTI_MAX_LEN + 32)
/* Alignment requirements */
#define WCD_SPI_RW_MIN_ALIGN WCD_SPI_WORD_BYTE_CNT
@@ -148,6 +155,10 @@ struct wcd_spi_priv {
/* Completion object to indicate system resume completion */
struct completion resume_comp;
+
+ /* Buffers to hold memory used for transfers */
+ void *tx_buf;
+ void *rx_buf;
};
enum xfer_request {
@@ -229,17 +240,18 @@ static int wcd_spi_read_single(struct spi_device *spi,
struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
struct spi_transfer *tx_xfer = &wcd_spi->xfer2[0];
struct spi_transfer *rx_xfer = &wcd_spi->xfer2[1];
- u8 *tx_buf;
+ u8 *tx_buf = wcd_spi->tx_buf;
u32 frame = 0;
int ret;
dev_dbg(&spi->dev, "%s: remote_addr = 0x%x\n",
__func__, remote_addr);
- tx_buf = kzalloc(WCD_SPI_READ_SINGLE_LEN,
- GFP_KERNEL | GFP_DMA);
- if (!tx_buf)
+ if (!tx_buf) {
+ dev_err(&spi->dev, "%s: tx_buf not allocated\n",
+ __func__);
return -ENOMEM;
+ }
frame |= WCD_SPI_READ_FRAME_OPCODE;
frame |= remote_addr & WCD_CMD_ADDR_MASK;
@@ -255,7 +267,6 @@ static int wcd_spi_read_single(struct spi_device *spi,
rx_xfer->len = sizeof(*val);
ret = spi_sync(spi, &wcd_spi->msg2);
- kfree(tx_buf);
return ret;
}
@@ -266,8 +277,8 @@ static int wcd_spi_read_multi(struct spi_device *spi,
{
struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
struct spi_transfer *xfer = &wcd_spi->xfer1;
- u8 *tx_buf;
- u8 *rx_buf;
+ u8 *tx_buf = wcd_spi->tx_buf;
+ u8 *rx_buf = wcd_spi->rx_buf;
u32 frame = 0;
int ret;
@@ -277,15 +288,9 @@ static int wcd_spi_read_multi(struct spi_device *spi,
frame |= WCD_SPI_FREAD_FRAME_OPCODE;
frame |= remote_addr & WCD_CMD_ADDR_MASK;
- tx_buf = kzalloc(WCD_SPI_CMD_FREAD_LEN + len,
- GFP_KERNEL | GFP_DMA);
- if (!tx_buf)
- return -ENOMEM;
-
- rx_buf = kzalloc(WCD_SPI_CMD_FREAD_LEN + len,
- GFP_KERNEL | GFP_DMA);
- if (!rx_buf) {
- kfree(tx_buf);
+ if (!tx_buf || !rx_buf) {
+ dev_err(&spi->dev, "%s: %s not allocated\n", __func__,
+ (!tx_buf) ? "tx_buf" : "rx_buf");
return -ENOMEM;
}
@@ -305,8 +310,6 @@ static int wcd_spi_read_multi(struct spi_device *spi,
memcpy(data, rx_buf + WCD_SPI_CMD_FREAD_LEN, len);
done:
- kfree(tx_buf);
- kfree(rx_buf);
return ret;
}
@@ -343,7 +346,7 @@ static int wcd_spi_write_multi(struct spi_device *spi,
struct wcd_spi_priv *wcd_spi = spi_get_drvdata(spi);
struct spi_transfer *xfer = &wcd_spi->xfer1;
u32 frame = 0;
- u8 *tx_buf;
+ u8 *tx_buf = wcd_spi->tx_buf;
int xfer_len, ret;
dev_dbg(&spi->dev, "%s: addr = 0x%x len = %zd\n",
@@ -355,9 +358,11 @@ static int wcd_spi_write_multi(struct spi_device *spi,
frame = cpu_to_be32(frame);
xfer_len = len + sizeof(frame);
- tx_buf = kzalloc(xfer_len, GFP_KERNEL);
- if (!tx_buf)
+ if (!tx_buf) {
+ dev_err(&spi->dev, "%s: tx_buf not allocated\n",
+ __func__);
return -ENOMEM;
+ }
memcpy(tx_buf, &frame, sizeof(frame));
memcpy(tx_buf + sizeof(frame), data, len);
@@ -371,8 +376,6 @@ static int wcd_spi_write_multi(struct spi_device *spi,
dev_err(&spi->dev,
"%s: Failed, addr = 0x%x, len = %zd\n",
__func__, remote_addr, len);
- kfree(tx_buf);
-
return ret;
}
@@ -1330,6 +1333,23 @@ static int wcd_spi_component_bind(struct device *dev,
spi_message_init(&wcd_spi->msg2);
spi_message_add_tail(&wcd_spi->xfer2[0], &wcd_spi->msg2);
spi_message_add_tail(&wcd_spi->xfer2[1], &wcd_spi->msg2);
+
+ /* Pre-allocate the buffers */
+ wcd_spi->tx_buf = kzalloc(WCD_SPI_RW_MAX_BUF_SIZE,
+ GFP_KERNEL | GFP_DMA);
+ if (!wcd_spi->tx_buf) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ wcd_spi->rx_buf = kzalloc(WCD_SPI_RW_MAX_BUF_SIZE,
+ GFP_KERNEL | GFP_DMA);
+ if (!wcd_spi->rx_buf) {
+ kfree(wcd_spi->tx_buf);
+ wcd_spi->tx_buf = NULL;
+ ret = -ENOMEM;
+ goto done;
+ }
done:
return ret;
}
@@ -1347,6 +1367,11 @@ static void wcd_spi_component_unbind(struct device *dev,
spi_transfer_del(&wcd_spi->xfer1);
spi_transfer_del(&wcd_spi->xfer2[0]);
spi_transfer_del(&wcd_spi->xfer2[1]);
+
+ kfree(wcd_spi->tx_buf);
+ kfree(wcd_spi->rx_buf);
+ wcd_spi->tx_buf = NULL;
+ wcd_spi->rx_buf = NULL;
}
static const struct component_ops wcd_spi_component_ops = {
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index 192d9291a8f3..cc8e45d77fcd 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -798,11 +798,13 @@ int wcd934x_bringup(struct wcd9xxx *wcd9xxx)
regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x01);
regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x19);
regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x15);
+ /* Add 1msec delay for VOUT to settle */
+ usleep_range(1000, 1100);
regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
- regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x3);
regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x7);
+ regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
return 0;
}
@@ -8277,6 +8279,9 @@ static int __tavil_cdc_mclk_enable(struct tavil_priv *tavil,
WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr);
ret = __tavil_cdc_mclk_enable_locked(tavil, enable);
+ if (enable)
+ wcd_resmgr_set_sido_input_src(tavil->resmgr,
+ SIDO_SOURCE_RCO_BG);
WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr);
return ret;
@@ -8415,6 +8420,8 @@ static int __tavil_codec_internal_rco_ctrl(struct snd_soc_codec *codec,
__func__, ret);
goto done;
}
+ wcd_resmgr_set_sido_input_src(tavil->resmgr,
+ SIDO_SOURCE_RCO_BG);
ret = wcd_resmgr_enable_clk_block(tavil->resmgr,
WCD_CLK_RCO);
ret |= tavil_cdc_req_mclk_enable(tavil, false);
@@ -9816,18 +9823,23 @@ static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil)
{
int val, rc;
- __tavil_cdc_mclk_enable(tavil, true);
+ WCD9XXX_V2_BG_CLK_LOCK(tavil->resmgr);
+ __tavil_cdc_mclk_enable_locked(tavil, true);
regmap_update_bits(tavil->wcd9xxx->regmap,
WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x1E, 0x10);
regmap_update_bits(tavil->wcd9xxx->regmap,
WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x01, 0x01);
-
/*
* 5ms sleep required after enabling efuse control
* before checking the status.
*/
usleep_range(5000, 5500);
+ wcd_resmgr_set_sido_input_src(tavil->resmgr,
+ SIDO_SOURCE_RCO_BG);
+
+ WCD9XXX_V2_BG_CLK_UNLOCK(tavil->resmgr);
+
rc = regmap_read(tavil->wcd9xxx->regmap,
WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS, &val);
if (rc || (!(val & 0x01)))
diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.c b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
index bd92ccc9e009..f16fc05a5eaa 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.c
@@ -25,8 +25,7 @@
#define WCD93XX_CDC_CLK_RST_CTRL_MCLK_CONTROL 0x0d41
#define WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL 0x0d42
-static void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
- int sido_src);
+
static const char *wcd_resmgr_clk_type_to_str(enum wcd_clock_type clk_type)
{
if (clk_type == WCD_CLK_OFF)
@@ -267,8 +266,6 @@ static int wcd_resmgr_enable_clk_mclk(struct wcd9xxx_resmgr_v2 *resmgr)
0x01, 0x01);
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD934X_CODEC_RPM_CLK_GATE, 0x03, 0x00);
- wcd_resmgr_set_sido_input_src(resmgr,
- SIDO_SOURCE_RCO_BG);
} else {
wcd_resmgr_codec_reg_update_bits(resmgr,
WCD93XX_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
@@ -515,7 +512,7 @@ int wcd_resmgr_enable_clk_block(struct wcd9xxx_resmgr_v2 *resmgr,
return ret;
}
-static void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
+void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
int sido_src)
{
if (!resmgr)
@@ -553,6 +550,7 @@ static void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
pr_debug("%s: sido input src to external\n", __func__);
}
}
+EXPORT_SYMBOL(wcd_resmgr_set_sido_input_src);
/*
* wcd_resmgr_set_sido_input_src_locked:
diff --git a/sound/soc/codecs/wcd9xxx-resmgr-v2.h b/sound/soc/codecs/wcd9xxx-resmgr-v2.h
index f605a249a620..e831ba61e9c2 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr-v2.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr-v2.h
@@ -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
@@ -87,4 +87,7 @@ int wcd_resmgr_get_clk_type(struct wcd9xxx_resmgr_v2 *resmgr);
void wcd_resmgr_post_ssr_v2(struct wcd9xxx_resmgr_v2 *resmgr);
void wcd_resmgr_set_sido_input_src_locked(struct wcd9xxx_resmgr_v2 *resmgr,
int sido_src);
+void wcd_resmgr_set_sido_input_src(struct wcd9xxx_resmgr_v2 *resmgr,
+ int sido_src);
+
#endif
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index 676c3b0335ef..eaaca97e2b8e 100644
--- a/sound/soc/codecs/wsa881x.c
+++ b/sound/soc/codecs/wsa881x.c
@@ -104,6 +104,7 @@ struct wsa881x_priv {
int state;
struct delayed_work ocp_ctl_work;
struct device_node *wsa_rst_np;
+ int pa_mute;
};
#define SWR_SLV_MAX_REG_ADDR 0x390
@@ -171,9 +172,41 @@ static int wsa_pa_gain_put(struct snd_kcontrol *kcontrol,
return 0;
}
-static const struct snd_kcontrol_new wsa_analog_gain_controls[] = {
+static int wsa881x_get_mute(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = wsa881x->pa_mute;
+
+ return 0;
+}
+
+static int wsa881x_set_mute(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
+ int value = ucontrol->value.integer.value[0];
+
+ dev_dbg(codec->dev, "%s: mute current %d, new %d\n",
+ __func__, wsa881x->pa_mute, value);
+
+ if (value)
+ snd_soc_update_bits(codec, WSA881X_SPKR_DRV_EN, 0x80, 0x00);
+ wsa881x->pa_mute = value;
+
+ return 0;
+}
+
+
+static const struct snd_kcontrol_new wsa_snd_controls[] = {
SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum,
wsa_pa_gain_get, wsa_pa_gain_put),
+ SOC_SINGLE_EXT("WSA PA Mute", SND_SOC_NOPM, 0, 1, 0,
+ wsa881x_get_mute, wsa881x_set_mute),
};
static int codec_debug_open(struct inode *inode, struct file *file)
@@ -1050,8 +1083,8 @@ static int wsa881x_probe(struct snd_soc_codec *codec)
wsa881x->tz_pdata.codec = codec;
wsa881x->tz_pdata.wsa_temp_reg_read = wsa881x_temp_reg_read;
wsa881x_init_thermal(&wsa881x->tz_pdata);
- snd_soc_add_codec_controls(codec, wsa_analog_gain_controls,
- ARRAY_SIZE(wsa_analog_gain_controls));
+ snd_soc_add_codec_controls(codec, wsa_snd_controls,
+ ARRAY_SIZE(wsa_snd_controls));
INIT_DELAYED_WORK(&wsa881x->ocp_ctl_work, wsa881x_ocp_ctl_work);
return 0;
}
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index d2c99bcc4626..ec02cdf3ca3c 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -5394,7 +5394,6 @@ static struct snd_soc_dai_link msm_tasha_fe_dai_links[] = {
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
.dpcm_playback = 1,
- .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
index 8e986a74ffff..2929ea0d735b 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -45,6 +45,7 @@
#include <sound/msm-dts-eagle.h>
#include "msm-pcm-routing-v2.h"
+#include "msm-qti-pp-config.h"
#define DSP_PP_BUFFERING_IN_MSEC 25
#define PARTIAL_DRAIN_ACK_EARLY_BY_MSEC 150
@@ -543,12 +544,19 @@ static void compr_event_handler(uint32_t opcode,
unsigned long flags;
uint64_t read_size;
uint32_t *buff_addr;
+ struct snd_soc_pcm_runtime *rtd;
+ int ret = 0;
if (!prtd) {
pr_err("%s: prtd is NULL\n", __func__);
return;
}
cstream = prtd->cstream;
+ if (!cstream) {
+ pr_err("%s: cstream is NULL\n", __func__);
+ return;
+ }
+
ac = prtd->audio_client;
/*
@@ -716,6 +724,23 @@ static void compr_event_handler(uint32_t opcode,
prtd->gapless_state.gapless_transition = 0;
spin_unlock_irqrestore(&prtd->lock, flags);
break;
+ case ASM_STREAM_PP_EVENT:
+ pr_debug("%s: ASM_STREAM_PP_EVENT\n", __func__);
+ rtd = cstream->private_data;
+ if (!rtd) {
+ pr_err("%s: rtd is NULL\n", __func__);
+ return;
+ }
+
+ ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK,
+ payload);
+ if (ret) {
+ pr_err("%s: failed to inform mixer ctrl. err = %d\n",
+ __func__, ret);
+ return;
+ }
+
+ break;
case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY: {
pr_debug("ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY\n");
@@ -815,6 +840,10 @@ static void compr_event_handler(uint32_t opcode,
}
atomic_set(&prtd->close, 0);
break;
+ case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
+ pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:",
+ __func__);
+ break;
default:
break;
}
@@ -3578,6 +3607,65 @@ end:
return rc;
}
+static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ unsigned long fe_id = kcontrol->private_value;
+ struct msm_compr_pdata *pdata = (struct msm_compr_pdata *)
+ snd_soc_component_get_drvdata(comp);
+ struct snd_compr_stream *cstream = NULL;
+ struct msm_compr_audio *prtd;
+ int ret = 0, param_length = 0;
+
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received invalid fe_id %lu\n",
+ __func__, fe_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cstream = pdata->cstream[fe_id];
+ if (cstream == NULL) {
+ pr_err("%s cstream is null.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ prtd = cstream->runtime->private_data;
+ if (!prtd) {
+ pr_err("%s: prtd is null.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (prtd->audio_client == NULL) {
+ pr_err("%s: audio_client is null.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy(&param_length, ucontrol->value.bytes.data,
+ sizeof(param_length));
+ if ((param_length + sizeof(param_length))
+ >= sizeof(ucontrol->value.bytes.data)) {
+ pr_err("%s param length=%d exceeds limit",
+ __func__, param_length);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = q6asm_send_stream_cmd(prtd->audio_client,
+ ASM_STREAM_CMD_REGISTER_PP_EVENTS,
+ ucontrol->value.bytes.data + sizeof(param_length),
+ param_length);
+ if (ret < 0)
+ pr_err("%s: failed to register pp event. err = %d\n",
+ __func__, ret);
+done:
+ return ret;
+}
+
static int msm_compr_gapless_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -3854,6 +3942,117 @@ static int msm_compr_add_query_audio_effect_control(
return 0;
}
+static int msm_compr_add_audio_adsp_stream_cmd_control(
+ struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = DSP_STREAM_CMD;
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+ struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_adsp_stream_cmd_info,
+ .put = msm_compr_adsp_stream_cmd_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s NULL rtd\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+ fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
+ fe_audio_adsp_stream_cmd_config_control[0].private_value =
+ rtd->dai_link->be_id;
+ pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+ ret = snd_soc_add_platform_controls(rtd->platform,
+ fe_audio_adsp_stream_cmd_config_control,
+ ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
+ if (ret < 0)
+ pr_err("%s: failed to add ctl %s. err = %d\n",
+ __func__, mixer_str, ret);
+
+ kfree(mixer_str);
+done:
+ return ret;
+}
+
+static int msm_compr_add_audio_adsp_stream_callback_control(
+ struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+ struct snd_kcontrol *kctl;
+
+ struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_adsp_stream_callback_info,
+ .get = msm_adsp_stream_callback_get,
+ .put = msm_adsp_stream_callback_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s: rtd is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+ fe_audio_adsp_callback_config_control[0].name = mixer_str;
+ fe_audio_adsp_callback_config_control[0].private_value =
+ rtd->dai_link->be_id;
+ pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+ ret = snd_soc_add_platform_controls(rtd->platform,
+ fe_audio_adsp_callback_config_control,
+ ARRAY_SIZE(fe_audio_adsp_callback_config_control));
+ if (ret < 0) {
+ pr_err("%s: failed to add ctl %s. err = %d\n",
+ __func__, mixer_str, ret);
+ ret = -EINVAL;
+ goto free_mixer_str;
+ }
+
+ kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
+ if (!kctl) {
+ pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
+ ret = -EINVAL;
+ goto free_mixer_str;
+ }
+
+ kctl->private_data = NULL;
+free_mixer_str:
+ kfree(mixer_str);
+done:
+ return ret;
+}
+
static int msm_compr_add_dec_runtime_params_control(
struct snd_soc_pcm_runtime *rtd)
{
@@ -4048,6 +4247,16 @@ static int msm_compr_new(struct snd_soc_pcm_runtime *rtd)
pr_err("%s: Could not add Compr Audio Effects Control\n",
__func__);
+ rc = msm_compr_add_audio_adsp_stream_cmd_control(rtd);
+ if (rc)
+ pr_err("%s: Could not add Compr ADSP Stream Cmd Control\n",
+ __func__);
+
+ rc = msm_compr_add_audio_adsp_stream_callback_control(rtd);
+ if (rc)
+ pr_err("%s: Could not add Compr ADSP Stream Callback Control\n",
+ __func__);
+
rc = msm_compr_add_query_audio_effect_control(rtd);
if (rc)
pr_err("%s: Could not add Compr Query Audio Effect Control\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-lsm-client.c b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
index ec4380036047..109e1a202ff2 100644
--- a/sound/soc/msm/qdsp6v2/msm-lsm-client.c
+++ b/sound/soc/msm/qdsp6v2/msm-lsm-client.c
@@ -1165,28 +1165,27 @@ static int msm_lsm_ioctl_shared(struct snd_pcm_substream *substream,
break;
case SNDRV_LSM_SET_FWK_MODE_CONFIG: {
- u32 *mode = NULL;
+ u32 mode;
- if (!arg) {
- dev_err(rtd->dev,
- "%s: Invalid param arg for ioctl %s session %d\n",
- __func__, "SNDRV_LSM_SET_FWK_MODE_CONFIG",
- prtd->lsm_client->session);
- rc = -EINVAL;
- break;
+ if (copy_from_user(&mode, arg, sizeof(mode))) {
+ dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n",
+ __func__, "LSM_SET_FWK_MODE_CONFIG");
+ return -EFAULT;
}
- mode = (u32 *)arg;
- if (prtd->lsm_client->event_mode == *mode) {
+
+ dev_dbg(rtd->dev, "%s: ioctl %s, enable = %d\n",
+ __func__, "SNDRV_LSM_SET_FWK_MODE_CONFIG", mode);
+ if (prtd->lsm_client->event_mode == mode) {
dev_dbg(rtd->dev,
"%s: mode for %d already set to %d\n",
- __func__, prtd->lsm_client->session, *mode);
+ __func__, prtd->lsm_client->session, mode);
rc = 0;
} else {
dev_dbg(rtd->dev, "%s: Event mode = %d\n",
- __func__, *mode);
- rc = q6lsm_set_fwk_mode_cfg(prtd->lsm_client, *mode);
+ __func__, mode);
+ rc = q6lsm_set_fwk_mode_cfg(prtd->lsm_client, mode);
if (!rc)
- prtd->lsm_client->event_mode = *mode;
+ prtd->lsm_client->event_mode = mode;
else
dev_err(rtd->dev,
"%s: set event mode failed %d\n",
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index 7928c3791f96..73eadfa4eebb 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -37,6 +37,7 @@
#include "msm-pcm-q6-v2.h"
#include "msm-pcm-routing-v2.h"
+#include "msm-qti-pp-config.h"
enum stream_state {
IDLE = 0,
@@ -147,6 +148,8 @@ static void event_handler(uint32_t opcode,
uint32_t idx = 0;
uint32_t size = 0;
uint8_t buf_index;
+ struct snd_soc_pcm_runtime *rtd;
+ int ret = 0;
switch (opcode) {
case ASM_DATA_EVENT_WRITE_DONE_V2: {
@@ -223,6 +226,29 @@ static void event_handler(uint32_t opcode,
}
break;
}
+ case ASM_STREAM_PP_EVENT: {
+ pr_debug("%s: ASM_STREAM_PP_EVENT\n", __func__);
+ if (!substream) {
+ pr_err("%s: substream is NULL.\n", __func__);
+ return;
+ }
+
+ rtd = substream->private_data;
+ if (!rtd) {
+ pr_err("%s: rtd is NULL\n", __func__);
+ return;
+ }
+
+ ret = msm_adsp_inform_mixer_ctl(rtd, DSP_STREAM_CALLBACK,
+ payload);
+ if (ret) {
+ pr_err("%s: failed to inform mixer ctl. err = %d\n",
+ __func__, ret);
+ return;
+ }
+
+ break;
+ }
case APR_BASIC_RSP_RESULT: {
switch (payload[0]) {
case ASM_SESSION_CMD_RUN_V2:
@@ -252,6 +278,10 @@ static void event_handler(uint32_t opcode,
}
atomic_set(&prtd->start, 1);
break;
+ case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
+ pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS:",
+ __func__);
+ break;
default:
pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
__func__, payload[0], payload[1]);
@@ -1036,6 +1066,177 @@ static struct snd_pcm_ops msm_pcm_ops = {
.mmap = msm_pcm_mmap,
};
+static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *pcm = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_platform *platform = snd_soc_component_to_platform(pcm);
+ struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
+ int ret = 0, param_length = 0;
+
+ if (!pdata) {
+ pr_err("%s pdata is NULL\n", __func__);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ prtd = substream->runtime->private_data;
+ if (prtd->audio_client == NULL) {
+ pr_err("%s prtd is null.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy(&param_length, ucontrol->value.bytes.data,
+ sizeof(param_length));
+ if ((param_length + sizeof(param_length))
+ >= sizeof(ucontrol->value.bytes.data)) {
+ pr_err("%s param length=%d exceeds limit",
+ __func__, param_length);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = q6asm_send_stream_cmd(prtd->audio_client,
+ ASM_STREAM_CMD_REGISTER_PP_EVENTS,
+ ucontrol->value.bytes.data + sizeof(param_length),
+ param_length);
+ if (ret < 0)
+ pr_err("%s: failed to register pp event. err = %d\n",
+ __func__, ret);
+done:
+ return ret;
+}
+
+static int msm_pcm_add_audio_adsp_stream_cmd_control(
+ struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = DSP_STREAM_CMD;
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+ struct snd_kcontrol_new fe_audio_adsp_stream_cmd_config_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_adsp_stream_cmd_info,
+ .put = msm_pcm_adsp_stream_cmd_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s rtd is NULL\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+ fe_audio_adsp_stream_cmd_config_control[0].name = mixer_str;
+ fe_audio_adsp_stream_cmd_config_control[0].private_value =
+ rtd->dai_link->be_id;
+ pr_debug("Registering new mixer ctl %s\n", mixer_str);
+ ret = snd_soc_add_platform_controls(rtd->platform,
+ fe_audio_adsp_stream_cmd_config_control,
+ ARRAY_SIZE(fe_audio_adsp_stream_cmd_config_control));
+ if (ret < 0)
+ pr_err("%s: failed add ctl %s. err = %d\n",
+ __func__, mixer_str, ret);
+
+ kfree(mixer_str);
+done:
+ return ret;
+}
+
+static int msm_pcm_add_audio_adsp_stream_callback_control(
+ struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = DSP_STREAM_CALLBACK;
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+ struct snd_kcontrol *kctl;
+
+ struct snd_kcontrol_new fe_audio_adsp_callback_config_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_adsp_stream_callback_info,
+ .get = msm_adsp_stream_callback_get,
+ .put = msm_adsp_stream_callback_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s NULL rtd\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pr_debug("%s: added new pcm FE with name %s, id %d, cpu dai %s, device no %d\n",
+ __func__, rtd->dai_link->name, rtd->dai_link->be_id,
+ rtd->dai_link->cpu_dai_name, rtd->pcm->device);
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+ if (!mixer_str) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name, rtd->pcm->device);
+ fe_audio_adsp_callback_config_control[0].name = mixer_str;
+ fe_audio_adsp_callback_config_control[0].private_value =
+ rtd->dai_link->be_id;
+ pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+ ret = snd_soc_add_platform_controls(rtd->platform,
+ fe_audio_adsp_callback_config_control,
+ ARRAY_SIZE(fe_audio_adsp_callback_config_control));
+ if (ret < 0) {
+ pr_err("%s: failed to add ctl %s. err = %d\n",
+ __func__, mixer_str, ret);
+ ret = -EINVAL;
+ goto free_mixer_str;
+ }
+
+ kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
+ if (!kctl) {
+ pr_err("%s: failed to get kctl %s.\n", __func__, mixer_str);
+ ret = -EINVAL;
+ goto free_mixer_str;
+ }
+
+ kctl->private_data = NULL;
+free_mixer_str:
+ kfree(mixer_str);
+done:
+ return ret;
+}
+
static int msm_pcm_set_volume(struct msm_audio *prtd, uint32_t volume)
{
int rc = 0;
@@ -1549,6 +1750,16 @@ static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
pr_err("%s: Could not add pcm Compress Control %d\n",
__func__, ret);
+ ret = msm_pcm_add_audio_adsp_stream_cmd_control(rtd);
+ if (ret)
+ pr_err("%s: Could not add pcm ADSP Stream Cmd Control\n",
+ __func__);
+
+ ret = msm_pcm_add_audio_adsp_stream_callback_control(rtd);
+ if (ret)
+ pr_err("%s: Could not add pcm ADSP Stream Callback Control\n",
+ __func__);
+
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 837a08488991..1d19f22bbc44 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -12937,6 +12937,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"VOIP_UL", NULL, "VOC_EXT_EC MUX"},
{"VoLTE_UL", NULL, "VOC_EXT_EC MUX"},
{"VOICE2_UL", NULL, "VOC_EXT_EC MUX"},
+ {"VoWLAN_UL", NULL, "VOC_EXT_EC MUX"},
{"VOICEMMODE1_UL", NULL, "VOC_EXT_EC MUX"},
{"VOICEMMODE2_UL", NULL, "VOC_EXT_EC MUX"},
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
index 6f463c079f19..d4e78604f868 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
@@ -817,6 +817,136 @@ static int msm_qti_pp_asphere_set(struct snd_kcontrol *kcontrol,
return 0;
}
+
+int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
+ const char *mixer_ctl_name,
+ uint32_t *payload)
+{
+ /* adsp pp event notifier */
+ struct snd_kcontrol *kctl;
+ struct snd_ctl_elem_value control;
+ uint32_t payload_size = 0;
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len = 0, ret = 0;
+
+ if (!rtd || !payload) {
+ pr_err("%s: %s is NULL\n", __func__,
+ (!rtd) ? "rtd" : "payload");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_ATOMIC);
+ if (!mixer_str) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ snprintf(mixer_str, ctl_len, "%s %d", mixer_ctl_name,
+ rtd->pcm->device);
+ kctl = snd_soc_card_get_kcontrol(rtd->card, mixer_str);
+ kfree(mixer_str);
+ if (!kctl) {
+ pr_err("%s: failed to get kctl.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ control.id = kctl->id;
+ payload_size = payload[0];
+ /* Copy complete payload */
+ memcpy(control.value.bytes.data, (void *)payload,
+ sizeof(payload_size) + payload_size);
+ kctl->put(kctl, &control);
+ if (rtd->card->snd_card == NULL) {
+ pr_err("%s: snd_card is null.\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ snd_ctl_notify(rtd->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_INFO,
+ &control.id);
+done:
+ return ret;
+}
+
+int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = 512;
+
+ return 0;
+}
+
+int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ uint32_t payload_size = 0, last_payload_size = 0;
+
+ /* fetch payload size in first four bytes */
+ memcpy(&payload_size, ucontrol->value.bytes.data, sizeof(uint32_t));
+
+ if (kcontrol->private_data == NULL) {
+ /* buffer is empty */
+ kcontrol->private_data =
+ kzalloc(payload_size + sizeof(payload_size),
+ GFP_ATOMIC);
+ if (kcontrol->private_data == NULL)
+ return -ENOMEM;
+ } else {
+ memcpy(&last_payload_size, kcontrol->private_data,
+ sizeof(uint32_t));
+ if (last_payload_size < payload_size) {
+ /* new payload size exceeds old one.
+ * reallocate buffer
+ */
+ kfree(kcontrol->private_data);
+ kcontrol->private_data =
+ kzalloc(payload_size + sizeof(payload_size),
+ GFP_ATOMIC);
+ if (kcontrol->private_data == NULL)
+ return -ENOMEM;
+ }
+ }
+
+ memcpy(kcontrol->private_data, ucontrol->value.bytes.data,
+ sizeof(uint32_t) + payload_size);
+
+ return 0;
+}
+
+int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ uint32_t payload_size = 0;
+
+ if (kcontrol->private_data == NULL) {
+ pr_err("%s: ASM Stream PP Event Data Unavailable\n", __func__);
+ return -EINVAL;
+ }
+
+ memcpy(&payload_size, kcontrol->private_data, sizeof(uint32_t));
+ memcpy(ucontrol->value.bytes.data, kcontrol->private_data,
+ sizeof(uint32_t) + payload_size);
+ kfree(kcontrol->private_data);
+ kcontrol->private_data = NULL;
+
+ return 0;
+}
+
+int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = 512;
+
+ return 0;
+}
+
static int msm_multichannel_ec_primary_mic_ch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
index f8a1da5e7702..70ce20fbd8f8 100644
--- a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
+++ b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.h
@@ -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
* only version 2 as published by the Free Software Foundation.
@@ -13,7 +13,17 @@
#define _MSM_QTI_PP_H_
#include <sound/soc.h>
-
+int msm_adsp_inform_mixer_ctl(struct snd_soc_pcm_runtime *rtd,
+ const char *mixer_ctl_name,
+ uint32_t *payload);
+int msm_adsp_stream_cmd_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+int msm_adsp_stream_callback_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int msm_adsp_stream_callback_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int msm_adsp_stream_callback_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
#ifdef CONFIG_QTI_PP
void msm_qti_pp_send_eq_values(int fedai_id);
int msm_qti_pp_send_stereo_to_custom_stereo_cmd(int port_id, int copp_idx,
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 79f27852391f..1ca99c3f9115 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -1094,6 +1094,65 @@ fail:
return NULL;
}
+int q6asm_send_stream_cmd(struct audio_client *ac, uint32_t opcode,
+ void *param, uint32_t params_length)
+{
+ char *asm_params = NULL;
+ struct apr_hdr hdr;
+ int sz, rc;
+
+ if (!param || !ac) {
+ pr_err("%s: %s is NULL\n", __func__,
+ (!param) ? "param" : "ac");
+ rc = -EINVAL;
+ goto done;
+ }
+
+ sz = sizeof(struct apr_hdr) + params_length;
+ asm_params = kzalloc(sz, GFP_KERNEL);
+ if (!asm_params) {
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ q6asm_add_hdr_async(ac, &hdr, sizeof(struct apr_hdr) +
+ params_length, TRUE);
+ atomic_set(&ac->cmd_state_pp, -1);
+ hdr.opcode = opcode;
+ memcpy(asm_params, &hdr, sizeof(struct apr_hdr));
+ memcpy(asm_params + sizeof(struct apr_hdr),
+ param, params_length);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);
+ if (rc < 0) {
+ pr_err("%s: audio adsp pp register failed\n", __func__);
+ rc = -EINVAL;
+ goto fail_send_param;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state_pp) >= 0), 1 * HZ);
+ if (!rc) {
+ pr_err("%s: timeout, adsp pp register\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_send_param;
+ }
+
+ if (atomic_read(&ac->cmd_state_pp) > 0) {
+ pr_err("%s: DSP returned error[%s] adsp pp register\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_send_param;
+ }
+
+ rc = 0;
+fail_send_param:
+ kfree(asm_params);
+done:
+ return rc;
+}
+
struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
{
struct audio_client *ac;
@@ -1615,6 +1674,8 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
int32_t ret = 0;
union asm_token_struct asm_token;
uint8_t buf_index;
+ char *pp_event_package = NULL;
+ uint32_t payload_size = 0;
if (ac == NULL) {
pr_err("%s: ac NULL\n", __func__);
@@ -1797,6 +1858,17 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
data->payload_size);
}
break;
+ case ASM_STREAM_CMD_REGISTER_PP_EVENTS:
+ pr_debug("%s: ASM_STREAM_CMD_REGISTER_PP_EVENTS session %d opcode 0x%x token 0x%x src %d dest %d\n",
+ __func__, ac->session,
+ data->opcode, data->token,
+ data->src_port, data->dest_port);
+ if (payload[1] != 0)
+ pr_err("%s: ASM get param error = %d, resuming\n",
+ __func__, payload[1]);
+ atomic_set(&ac->cmd_state_pp, payload[1]);
+ wake_up(&ac->cmd_wait);
+ break;
default:
pr_debug("%s: command[0x%x] not expecting rsp\n",
__func__, payload[0]);
@@ -1967,6 +2039,26 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
case ASM_SESSION_CMDRSP_GET_MTMX_STRTR_PARAMS_V2:
q6asm_process_mtmx_get_param_rsp(ac, (void *) payload);
break;
+ case ASM_STREAM_PP_EVENT:
+ pr_debug("%s: ASM_STREAM_PP_EVENT payload[0][0x%x] payload[1][0x%x]",
+ __func__, payload[0], payload[1]);
+ /* repack payload for asm_stream_pp_event
+ * package is composed of size + actual payload
+ */
+ payload_size = data->payload_size;
+ pp_event_package =
+ kzalloc(payload_size + sizeof(payload_size),
+ GFP_ATOMIC);
+ if (!pp_event_package)
+ return -ENOMEM;
+ memcpy((void *)pp_event_package,
+ &payload_size, sizeof(payload_size));
+ memcpy((void *)pp_event_package + sizeof(payload_size),
+ data->payload, payload_size);
+ ac->cb(data->opcode, data->token,
+ (void *)pp_event_package, ac->priv);
+ kfree(pp_event_package);
+ return 0;
case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2:
pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n",
__func__, ac->session, payload[0], payload[2],
diff --git a/sound/soc/msm/sdm660-ext-dai-links.c b/sound/soc/msm/sdm660-ext-dai-links.c
index f64074d442dc..1c03d8c9e797 100644
--- a/sound/soc/msm/sdm660-ext-dai-links.c
+++ b/sound/soc/msm/sdm660-ext-dai-links.c
@@ -335,7 +335,6 @@ static struct snd_soc_dai_link msm_ext_tasha_fe_dai[] = {
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
.dpcm_playback = 1,
- .dpcm_capture = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index d08e214ec6e7..223d88e25e05 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -2629,7 +2629,7 @@ sub do_run_test {
}
waitpid $child_pid, 0;
- $child_exit = $?;
+ $child_exit = $? >> 8;
my $end_time = time;
$test_time = $end_time - $start_time;